5

これについては多くの質問がありましたが、どれも役に立たないようです。そして、はい、私はこのレールがキャストされるのを見てきました。

私には、次のように多くの本を持っている著者がいます。

著者:

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

本:

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

authors#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 %>

...次のauthors_controllerメソッドを使用します。

def show
    @author = Author.find(params[:id])
    @book = @author.books.build
end

...および次の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

フォームにエラーメッセージが表示されない理由がわかりません。私はrailscastsの例に従い、@ author.books.buildの代わりに本のインスタンス変数をフォームに含める必要があると言っているので、後者をコントローラーに入れ、@bookをフォームに入れました-それでも役に立ちません。

助けてくれてありがとう!

4

2 に答える 2

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

(ちなみに、 @author が見つからない場合はどうなりますか。あなたはそのケースを処理していません。)

ここで、Author が見つかりましたが、@author.books.create が失敗する (false を返す) ため、show アクションをレンダリングします。

これは show テンプレートを使用しますが、show アクション コードを呼び出しません。(ちなみに、新しいページの方が適切な選択になる可能性があるため、ユーザーはもう一度作成を試みることができます。)

この時点で、@author は見つけた Author でインスタンス化されますが、@book ではインスタンス化されません。したがって、@book が呼び出された場合は nil になります。

あなたのショーテンプレートは

if @book.errors.any?

これは当てはまらないため、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

新しいテンプレートは

<% 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 %>
于 2012-10-19T10:30:39.613 に答える
1

Books コントローラー内 /books_controller.rb

def new
   @author = Author.find_by_id(params[:author_id])
   @book = @author.books.build
end

def create 
   @author = Author.find_by_id(params[:author_id])
   if @author
     @book = @author.books.build(params[:book])
     if @book.save
       flash[:notice] = "Book saved successfully"
       redirect_to author_path(@author)
     else
       render :new
     end
  else
   flash[:notice] = "Sorry no author found"
   redirect_to author_path
  end 
end

著者が存在しない場合は、エラー メッセージが表示された著者のインデックス ページにリダイレクトします。

そして、あなたの本の新しいフォームでは、本のエラーをリストすることができます

/books/new.html.erb

  <% if @book.errors.any? %>
    <div class="alert alert-block">
      <ul>
         <% @books.errors.full_messages.each do |msg| %>
             <li><%= msg %></li>
         <% end %>
     </ul>
   </div>
 <% end %>
于 2012-10-19T14:53:25.463 に答える