嵌套模型验证 - 不显示错误

dch*_*cke 5 ruby validation model-view-controller ruby-on-rails nested-forms

关于这一点有很多问题,但它们似乎都没有帮助.是的,我看过这个导演.

我有一个有很多书的作者,如下:

作者:

class Author < ActiveRecord::Base
  attr_accessible :name
  has_many :books, dependent: :destroy

  accepts_nested_attributes_for :books, allow_destroy: true

  validates :name, presence: true
  validates :name, length: { minimum: 3 }
end
Run Code Online (Sandbox Code Playgroud)

书:

class Book < ActiveRecord::Base
  attr_accessible :name, :year
  belongs_to :author

  validates :name, :year, presence: true
  validates :year, numericality: { only_integer: true, less_than_or_equal_to: Time.now.year }
end
Run Code Online (Sandbox Code Playgroud)

我创建了以下表单,以便在作者的作者中添加一本书#show:

<%= form_for([@author, @book], html: { class: "well" }) do |f| %>
<% if @book.errors.any? %>
    <div class="alert alert-block">
        <ul>
            <% @author.errors.full_messages.each do |msg| %>
                <li><%= msg %></li>
            <% end %>
        </ul>
    </div>
<% end %>
#labels and buttons...
<% end %>
Run Code Online (Sandbox Code Playgroud)

...使用以下authors_controller方法:

def show
    @author = Author.find(params[:id])
    @book = @author.books.build
end
Run Code Online (Sandbox Code Playgroud)

...以及以下books_controller方法:

def create
    @author = Author.find(params[:author_id])
    if @author.books.create(params[:book])
      redirect_to author_path(@author)
    else
      render action: :show
    end
  end
Run Code Online (Sandbox Code Playgroud)

我似乎无法弄清楚为什么表单不显示任何错误消息.我跟着railscasts的例子,他们说应该有一个表格的实例变量而不是@ author.books.build,所以我把后者放在控制器和表中的@book中 - 仍无济于事.

谢谢你的帮助!

Mar*_*rce 9

让我们一步一步.

您提交创建,然后输入您的创建操作

def create
  @author = Author.find(params[:author_id])
  if @author.books.create(params[:book])
    redirect_to author_path(@author)
  else
    render action: :show
  end
end
Run Code Online (Sandbox Code Playgroud)

(旁注,如果找不到@author怎么办.你没有处理那个案子.)

现在,找到了Author,但@ author.books.create失败(返回false),因此您呈现show动作.

这使用了show模板,但没有调用show动作代码.(旁注,也许新页面可能是更好的选择,因此用户可以尝试再次创建.)

此时@author被您找到的作者实例化,但不是@book.所以@book,如果被调用将是零.

你的节目模板呢

if @book.errors.any?
Run Code Online (Sandbox Code Playgroud)

这将不会是真的,所以if中的其余模板将被跳过.这就是没有错误的原因.

您不需要form_for来显示错误消息.如果您切换到使用新模板,则会有一个表单重试.

所以让我们切换到渲染新的.

Class BooksController < ApplicationController
  def new
    @author = Author.find(params[:author_id])
    @book = @author.books.build
  end

  def create
    @author = Author.find(params[:author_id])
    @book = @author.books.build(params[:book])
    if @author.save
      redirect_to author_path(@author)
    else
      render action: :new
    end
  end
Run Code Online (Sandbox Code Playgroud)

你的新模板将是

<% if @author.errors.any? %>
    <div class="alert alert-block">
        <ul>
            <% @author.errors.full_messages.each do |msg| %>
                <li><%= msg %></li>
            <% end %>
        </ul>
    </div>
<% end %>
<% if @book.errors.any? %>
    <div class="alert alert-block">
        <ul>
            <% @book.errors.full_messages.each do |msg| %>
                <li><%= msg %></li>
            <% end %>
        </ul>
    </div>
<% end %>

<%= form_for([@author, @book], html: { class: "well" }) do |f| %>
#labels and buttons...
<% end %>
Run Code Online (Sandbox Code Playgroud)