Ruby on Rails - 隐藏标记不会传入数据库

时间:2016-02-07 10:42:07

标签: mysql ruby-on-rails

对RoR来说真的很新,遇到了一个我无法找到答案的问题。

我有两个表,userbooks,我正在尝试使用联接表来匹配用户和图书,并在联接表中添加评分和审核列。 问题是除了book_id

之外,所有内容都传递到连接表中

查看

<%= form_for(current_user.user_book_collections.build) do |f| %>
      <div>
        <%= hidden_field_tag :book_id, current_book.id %>
        <%= f.label :rating %>
        <%= f.text_field :rating, class:"form-control" %> 
        <%= f.label :review %> (optional):
        <%= f.text_area :review, size: "24x8", placeholder: "Please enter a brief review... ", class:"form-control" %>
      </div>
      <p></p>
      <%= f.submit "Add to your collection", class:"btn btn-primary" %>
    <% end %>

current_usercurrent_book是分别分配用户和图书的方法。

控制器

def create
    @user_book_collection = current_user.user_book_collections.build(user_book_collection_params)
    if @user_book_collection.save
       flash[:success] = "Added to your collection"
       redirect_to mybooks_path
    else
       flash[:danger] = "Add was unsuccessful"
       redirect_to bookcollection_path
    end 
end 

private

   def user_book_collection_params
       params.require(:user_book_collection).permit( :book_id, :user_id, :review, :rating )
   end  
end

这是控制台中显示的内容:

  Parameters: {"utf8"=>"✓", "authenticity_token"=>"85gmzUO7ldQrevh/qnKwYO9mkd9lX77sG3xxJQV8Y46xZrkl5ifk665abPr79nOT91rO3oLcMSDgYL7BtR+/XQ==", "book_id"=>"6", "user_book_collection"=>{"rating"=>"s", "review"=>"asd"}, "commit"=>"Add to your collection"}

但是然后在控制台中检查记录我可以看到book_id没有通过,即使它已在参数中分配:

=> #<ActiveRecord::Associations::CollectionProxy [#<UserBookCollection id: 10, user_id: 7, book_id: nil, review: "asd", rating: "s", created_at: "2016-02-07 06:36:33", updated_at: "2016-02-07 06:36:33">

任何帮助都将不胜感激,谢谢。

3 个答案:

答案 0 :(得分:0)

这是因为您的表单是以book_id传递params[:book_id]的方式构建的,而不是params[:user_book_collection][:book_id]中传递的user_book_collection_params

使用:

f.hidden_field :book_id, value: current_book.id

答案 1 :(得分:0)

<%= f.hidden_field :book_id, current_book.id %>

使用form_for时,需要将输入方法绑定到表单对象(如上所述)。

答案 2 :(得分:0)

除了Rich Peck和Vasfeds的优秀答案之外,我建议你从REST的角度考虑你在做什么。

您希望用户能够将评论添加到图书中。请注意,这里的UserBookCollections只是一个丑陋的管道 - 不是真正用REST公开的资源。并且将其称为UserBookCollection有点误导,因为每个UserBookCollection实际上只是一个用户和一本书之间的链接。

此外,您希望避免在Rails中调用任何Collection,因为ActiveRecord使用该概念来表示可能加载或未加载的链接记录的集合 - you're going to confuse others

这是解决同一问题的一种方法

class User
  has_many :reviews
  has_many :books, through: :reviews
end

class Review
  belongs_to :user
  belongs_to :book 
end

class Book
  has_many :reviews, through: :reviews
end

很好,现在我们有一个对象,我们甚至不必解释它的作用。所以我们把它变成一个RESTful资源:

Rails.application.routes.draw do

  resources :reviews, only: [:show, :edit, :update, :destroy]

  resources :books do
    resources :reviews, only: [:new, :create, :index], module: :books
  end

  resources :users do
    resources :reviews, only: [:index], module: :users
  end
end

这为我们提供了具有上下文的路线:

         Prefix Verb   URI Pattern                           Controller#Action
    edit_review GET    /reviews/:id/edit(.:format)           reviews#edit
         review GET    /reviews/:id(.:format)                reviews#show
                PATCH  /reviews/:id(.:format)                reviews#update
                PUT    /reviews/:id(.:format)                reviews#update
                DELETE /reviews/:id(.:format)                reviews#destroy
   book_reviews GET    /books/:book_id/reviews(.:format)     books/reviews#index
                POST   /books/:book_id/reviews(.:format)     books/reviews#create
new_book_review GET    /books/:book_id/reviews/new(.:format) books/reviews#new
   user_reviews GET    /users/:user_id/reviews(.:format)     users/reviews#index

酷 - 现在我们有一个内置上下文的审查API。 RESTful路线本身告诉我们何时为某本书创建评论或查看特定用户的评论。

module: :books告诉rails将嵌套路由链接到“命名空间”控制器,而不是将所有内容都推送到ReviewsController

我们按如下方式设置控制器:

class ReviewsController < ApplicationController
  before_action :set_review, only: [:edit, :show, :update, :destroy]

  # GET /reviews/:id
  def show
  end 

  # GET /reviews
  def index
    @reviews = Review.all
  end

  # GET /reviews/:id/edit
  def edit
  end

  # PATCH /reviews/:id
  def update
    @review.update(review_params)
    respond_with(@review)
  end

  # DELETE /reviews/:id
  def destroy
    @review.destroy
    respond_with(@review)
  end

  private

    def set_review
      @review = Review.find(params[:id])
    end

    def review_params
      params.require(:review).permit(:rating, :body) # note that you don't need book_id in here.
    end

end
# app/controllers/books/reviews_controller.rb
class Books::ReviewsController < ReviewsController

  before_action :set_book

  # GET /books/:book_id/reviews
  def index
    @reviews = Review.eager_load(:user, :book).where(book_id: params[:book_id])
  end 

  # GET /books/:book_id/reviews/new
  def new
    @review = @book.find(params[:book_id]).reviews.new
  end

  # POST /books/:book_id/reviews
  def create
    @review = @book.reviews.new(review_params) do |review|
      review.user = current_user
    end
    respond_with(@review)
  end

  private
    def set_book
      @book = Book).find(params[:book_id])
    end
end
# app/controllers/users/reviews_controller.rb
class Users::ReviewsController < ApplicationController
  # GET /users/:user_id/reviews
  def index
    @reviews = Review.joins(:user, :book).where(user_id: params[:user_id])
  end
end

您可能会质疑为什么要使用3个控制器?它允许代码共享和自定义的非常干净的机制。您可以拥有不同的逻辑和视图,而无需创建大量ifswitch代码路径。在一个动作中有许多分支使得测试非常混乱并且违反了瘦的控制器范例。

表单看起来像这样:

# app/views/reviews/_fields.html.erb
<%= f.label :rating %>
<%= f.text_field :rating, class:"form-control" %> 
<%= f.label :body %> (optional):
<%= f.text_area :body, size: "24x8", placeholder: "Please enter a brief review... ", class:"form-control" %>
# app/views/books/reviews/new.erb
<%= form_for([@book, @review]) do |f| %>
  <%= render partial: 'reviews/fields', f: f %>
<% end %>
# app/views/books/edit.erb
<%= form_for(@review) do |f| %>
  <%= render partial: 'reviews/fields', f: f %>
<% end %>