シナリオ:has_manyアソシエーション(投稿には多くの作成者がいます)があり、作成者の属性を受け入れるためのネストされた投稿フォームがあります。
私が見つけたのは、post.update_attributes(params [:post])を呼び出すと、params [:post]はpostと追加するすべての作成者属性を含むハッシュであり、Railsにのみ要求する方法がないようです。特定の基準が満たされている場合、たとえば作成者のユーザー名がすでに存在する場合は、作成者を作成します。Railsが行うことは、usernameがモデルで一意性の検証を行っている場合に、update_attributesルーチンを失敗させてロールバックすることです。そうでない場合、IDを持たないレコード作成者がハッシュに含まれていると、Railsは新しいレコード作成者を追加します。
これで、Postコントローラーの更新アクションのコードは次のようになります。
def update
@post = Post.find(params[:id])
# custom code to work around by inspecting the author attributes
# and pre-inserting the association of existing authors into the testrun's author
# collection
params[:post][:authors_attributes].values.each do |author_attribute|
if author_attribute[:id].nil? and author_attribute[:username].present?
existing_author = Author.find_by_username(author_attribute[:username])
if existing_author.present?
author_attribute[:id] = existing_author.id
@testrun.authors << existing_author
end
end
end
if @post.update_attributes(params[:post])
flash[:success] = 'great!'
else
flash[:error] = 'Urgg!'
end
redirect_to ...
end
私が逃したこれを処理するためのより良い方法はありますか?
編集:@ Robd'Apiceに感謝します。私に代わって、accepts_nested_attributes_forがモデルに挿入するデフォルトのauthors_attributes =関数をオーバーライドすることを検討してくれたので、より良いものを思いつくことができました。
def authors_attributes=(authors_attributes)
authors_attributes.values.each do |author_attributes|
if author_attributes[:id].nil? and author_attributes[:username].present?
author = Radar.find_by_username(radar_attributes[:username])
if author.present?
author_attributes[:id] = author.id
self.authors << author
end
end
end
assign_nested_attributes_for_collection_association(:authors, authors_attributes, mass_assignment_options)
end
しかし、私はそれに完全に満足していません。1つは、呼び出し元からの属性ハッシュを直接マックしているため、これらのハッシュに対してロジックがどのように機能するかを理解する必要があります(たとえば、:idが設定されているかどうか)。 、ここに収まるように簡単ではない関数を呼び出しています。特定の条件が満たされない場合にのみ新しいレコードを作成するように「accepts_nested_attributes_for」に指示する方法があると便利です。1対1の関連付けには、同様のことを行う:update_onlyフラグがありますが、これは1対多の関係にはありません。
そこにもっと良い解決策はありますか?