私はこれを自分で理解するのに苦労しているので、うまく説明できることを願っています。ネストされたモデルを持つフォームがあります。簡略化したバージョンは次のとおりです (Rails 3.0.13 を使用)。
#parent.rb
class Parent < ActiveRecord::Base
has_many :children, :dependent => destroy
accepts_nested_attributes_for :children, :allow_destroy => true
validates_presence_of :thing
validate :children_unique
def children_unique
errors[:base] << "You have the same child listed more than once!" if self.children.map{|x| [child.name, child.age]} != self.children.map{|x| [child.name, child.age]}.uniq
end
end
#child.rb
class Child < ActiveRecord::Base
belongs_to :parents
end
#parents_controller.rb
class ParentsController < ApplicationController
load_and_authorize_resource :parent #Using cancan for authorization. This calls @parent = Parent.find(params[:id]); authorize! :update, @parent; at the start of the update method
def update
if @parent.update_attributes(params[:operation])
redirect_to @parent.admission, :notice => 'Operation was updated successfully'
else
flash.now[:warning] = "Parent was NOT updated!"
render :action => "edit"
end
end
end
これまでのところすべてかなり標準的です。私のフォームもかなり標準的な方法で設定されています。parent_form.fields_for :children
fields_for ブロック内で子のパーシャルを呼び出してレンダリングします。各子部分フォームには削除リンクが含まれており、クリックすると javascript を使用して隠しフィールドが設定されるため、_destroy の属性が「1」に設定され、部分フォームが非表示になります。
これはほとんどの場合うまく機能しますが、私が見つけた奇妙な問題は次のとおりです。
既に 2 人の子を持つ既存の親を編集している場合、それらの子の 1 つを削除してから、「もの」を空白に設定すると、フォームは期待どおりに検証に失敗し (「もの」が存在しないため)、編集ビューが再レンダリングされます。その結果、削除した子が再び表示されます。その非表示の _destroy フィールドは「true」に設定されており、「thing」に再度入力してフォームを送信すると、更新された親には子が 1 つしかありません。
ネストされた子 div に条件付きスタイル タグを追加することでこれに対処し<div class='fields'<%= " style='display: none;'" if f.object._destroy %>>
、レコードを更新する前に削除された場合は表示されないようにしました。これは目的を達成しますが、これを行って空の「もの」フィールドを修正せずにフォームを送信すると、モデルは再び検証に失敗し、表示される次の編集フォームで、以前に削除されたものと同じ新しい子を追加します「もの」フィールドに入力するchildren_unique
と、同一の子の最初の _delete 属性が「true」に設定されていても、モデルは検証に失敗します。
明らかに、私はここで自分自身を結びつけており、膨大な数の代替アプローチと修正を試みましたが、これがこれまでに思いついた最高のものです. それは非常に近いですが、実際にはおそらく実際には起こらないこの奇妙なエッジケースがまだありますが、これは、コントローラーとモデルが相互作用する方法をよく理解していないことを示唆しています.
誰かが私を正すことができますか?