Form_for助手

时间:2014-03-04 08:06:53

标签: ruby-on-rails forms associations

我有2个模型通过连接表相互关联:

class Book < ActiveRecord::Base
  has_many :reviews
end

class Reader < ActiveRecord::Base
  has_many :reviews
end

class Reviews < ActiveRecord::Base
  belongs_to :reader
  belongs_to :book
end

现在,我可以在路线上更新评论(我在控制台中手动创建):

readers/:id/books 

上面的路线是使用rails的成员方法创建的:

resources :readers
  member do
    get 'books'
  end
end

评论控制器中的更新操作(评论#update)定义如下:

def update
  @reader = current_reader
  @review = Review.find_by_reader_id(@reader.id)
  @book = Book.find(params[:review][:book]
  if @reader.books.include?(@book)
     @review.update_attributes(review_params)
     redirect_to (@reader)
  else
     flash[:error] = 'You can only edit reviews that belong to you'
  end
end

我的form_for评论(评论#update)看起来像这样: 读者评论:

<% book.reviews.each do |review| %>
  <% if current_reader == (review.reader) %>
  <%= review.content %> written by <%= review.reader.name %>
    <% if current_reader.reviews.include?(review) %>
      <%= form_for ([book, review]) do |f| %>
        <div class="field">
         <%= f.hidden_field :book, :value => book.id %>
         <%= f.text_area :content, placeholder: "compose new review" %>
        </div>
        <%= f.submit "Update", class: "btn btn-large btn-primary" %>
     <% else %>
       <%= form_for ([book, review]) do |f| %>
         <div class="field">
           <%= f.hidden_field :book, :value => book.id %>
           <%= f.text_area :content, placeholder: "compose new review" %>
         </div>
         <%= f.submit "Post", class: "btn btn-large btn-primary" %>
       <% end %>
     <% end %>
  <% end %>
<% end %>

以上内容适用于更新。但第二种形式没有。

我的目的是检查评论=&gt;如果有的话 - 显示一个表格,以便读者可以更新评论;如果没有,则显示表单,以便读者可以创建评论。我在评论控制器中有一个私有方法,它检查以确保读者在执行任何操作之前都有一本书(我猜想是一个before_action方法)。

第一种形式运作良好(更新形式)但第二种形式不适用 - 表格根本不显示。我尝试了各种各样的东西来显示表格,但没有运气。你能否请我确定解决这个问题的最佳方法?

非常感谢!

3 个答案:

答案 0 :(得分:0)

可能有几个问题:

<强> ELSIF

您的其他表单未显示的可能原因是您的elsif逻辑不正确

我查看了.include? Ruby函数,它似乎只适用于数组。为什么不尝试使用.exists?

<% elseif !current_reader.reviews.exists?(review) %>

您可能必须使用review.id或类似内容才能获得正确的回复。如果不这样做,为什么不使用<% else %>


<强>的form_for

第二个问题可能是您的第二个form_for

<%= form_for [:book, review] do |f| %>

您当前正在将名为book的本地变量传递给form_for构建器。虽然这可能是正确的(我找不到您对创建book的参考),但我发现最好在嵌套表单中放置一个符号(以显示Rails需要使用哪些数据)

答案 1 :(得分:0)

您可以尝试使用else代替elsif !current_reader.reviews.include?(review)吗?

此外,它是elsif而不是elseif。问题不应该因为这个问题 - 如果是这种情况,页面就不会首先加载。

答案 2 :(得分:0)

<强>更新 我通过更新表单修复了我的第一个错误: 读者评论:

<% book.reviews.where(reader_id: current_reader.id).each do |review| %>
  <li>
    <span><%= review.content %> writen by <%= review.reader.name %> </span
    <%= form_for ([book, review]) do |f| %>
      <div class="field">
        <%= f.hidden_field :book, :value => book.id %>
        <%= f.text_area :content, placeholder: "compose new review" %>
      </div>
        <%= f.submit "Update", class: "btn btn-large btn-primary" %>
    <% end %>
  </li>
    <% if book.reviews.where(reader_id: current_reader.id).size == 0 %>
      <%= form_for ([book, book.reviews.build]) do |f| %>
        <div class="field">
          <%= f.hidden_field :book, :value => book.id %>
          <%= f.text_area :content, placeholder: "compose new review" %>
        </div>
        <%= f.submit "Post", class: "btn btn-large btn-primary" %>
    <% end %>
  <% end %>
<% end %>

显示表单(发布和更新)。 但是当我尝试发布新评论时出现此错误:

(rdb:35) @review
#<Review id: nil, reader_id: 101, content: "Trial", created_at: nil, updated_at: nil, book_id: nil>
(rdb:35) review_params
Unpermitted parameters: book
{"content"=>"Trial"}
(rdb:35) 

所以我更改了我的创建操作以进行审核,以确保book_id不是nill:

def create
  @reader = current_reader
  # @book = Book.find(params[:book_id])
  @book = Book.find(params[:review][:book])
  if @reader.reviews.where(book_id: @book.id).exists? 
    flash[:error] = "You already reviewed this book"
  else
    @review = current_reader.reviews.create(:book_id => params[:book_id.to_i, :content => review_params[:content])
    debugger
    if @review.save
      flash[:success] = "Review created"
      redirect_to reader_path(@reader)
    else
      flash[:error] = "You can only review books that are in your library"
      redirect_to reader_path(@reader)
    end
  end
end

还改变了我定义review_params的方式:

def review_params
  params.require(:review).permit(:content, :book_id)
end

所有这些变化都给出了预期的结果。我的代码并不干,但对我来说最重要的事情就是让事情发挥作用。这是希望我不再打破它。感谢您的帮助@RichPeck