在表单中显示关联错误

时间:2012-03-25 22:34:08

标签: ruby-on-rails ruby ruby-on-rails-3 associations

我有一个模型:review.rb

class Review < ActiveRecord::Base
  validates :title, :presence => true
  belongs_to :product
end

model:product.rb

class Product < ActiveRecord::Base
  validates :name, :presence => true

  has_many :reviews, :dependent => :destroy
end

和此表单:_form.html.haml

=form_for([@product, @product.reviews.build]) do |f|
  .field
    =f.label :title
    %br
    =f.text_field :title

有了这个reviews_controller:

def create
  @product = Product.find(params[:product_id])
  @review = @product.reviews.create(params[:review])
  redirect_to product_path(@product)
end

当我添加没有标题的评论时,评论不会被创建,因为标题是必需的(这是好的)。我不知道如何在这个关联中显示错误。

我试过了:

=form_for([@product, @product.reviews.build]) do |f|
  -if @product.reviews.errors.any?
    .errors
      %h2
        =pluralize(@product.reviews.errors.count, "error")
      %ul
        =@product.reviews.errors.full_messages.each do |msg|
          %li
            =msg

但得到了这个错误:

undefined method `errors' for #<ActiveRecord::Relation:0x00000103e31df0>

我试过了:

  -if @review.errors.any?
    .errors
      %h2
        =pluralize(@review.errors.count, "error")
      %ul
        =@review.errors.full_messages.each do |msg|
          %li
            =msg

得到了:

undefined method `errors' for nil:NilClass

在I:

中的控制器中
    raise @review.errors.inspect

我可以看到错误:

#<ActiveModel::Errors:0x00000103d88c28 @base=#<Review id: nil, title: "", description: "", rating: nil, helpful: nil, product_id: 1, created_at: nil, updated_at: nil>, @messages={:title=>["can't be blank", "is too short (minimum is 5 characters)"]}>

我忘记了什么?如何显示错误?

谢谢

1 个答案:

答案 0 :(得分:3)

当您拨打redirect_to product_path(@product)时,您正在调用其他控制器操作,即Products#show操作。您的视图将被重置的实例变量。您可能没有在此操作中初始化@review实例变量,这就是您获得异常的原因。

你想要的是这样的

# posts_controller.rb
def show
  @product = Product.find(params[:product_id])
  @review = @product.reviews.build
end

# show.html.erb
= form_for([@product, @review]) do |f|
  -if @review.errors.any?
    .errors
      %h2
        =pluralize(@review.errors.count, "error")
      %ul
        =@review.errors.full_messages.each do |msg|
          %li
            =msg

# reviews_controller.rb
def create
  @product = Product.find(params[:product_id])
  @review = @product.reviews.build(params[:review])
  if @review.save
    redirect_to product_path(@product)
  else
    render 'products/show'
  end
end

关键是如果review创建失败,您将重新呈现具有相同实例变量的页面。