2009-07-30 7 views
22

2.1.xからRails 2.3.3にアップグレードしましたが、私はメソッドを見つけようとしています。このメソッドを使用して既存のネストされたオブジェクトを更新することはできますが、新しいネストされたオブジェクトを作成するためには使用できません。私は次のように、ネストされたNoteで、新しいProductを作成しようとaccepts_nested_attributes_forを使用して入れ子になったオブジェクトを作成する方法

class Product < ActiveRecord::Base 
    has_many :notes 
    accepts_nested_attributes_for :notes 
end 

class Note < ActiveRecord::Base 
    belongs_to :product 
    validates_presence_of :product_id, :body 
end 

:不自然な例を考えると

ActiveRecord::RecordInvalid: Validation failed: Notes product can't be blank 

params = {:name => 'Test', :notes_attributes => {'0' => {'body' => 'Body'}}} 
p = Product.new(params) 
p.save! 

それはメッセージと妥当性が確認されません私はこれがなぜ起こっているのか理解しています - それはNoteクラスのvalidates_presence_of :product_idのためであり、新しいレコードを保存するときにProductオブジェクトにはidがありません。しかし、私はこの検証を削除したくありません。私はそれを削除するのは間違いだと思います。

Productを手動で作成してからNoteを追加することで問題を解決することもできますが、これはaccepts_nested_attributes_forの単純さに反するものです。

新しいレコードにネストされたオブジェクトを作成する標準的な方法はありますか?

答えて

16

これは一般的な循環依存関係の問題です。チェックアウトの価値があるexisting LightHouse ticketがあります。

これはRails 3で大幅に改善されると思いますが、その間に回避策を講じる必要があります。 1つの解決策は、検証を条件付きにするためにネストするときに設定する仮想属性を設定することです。

class Note < ActiveRecord::Base 
    belongs_to :product 
    validates_presence_of :product_id, :unless => :nested 
    attr_accessor :nested 
end 

この属性は、フォームの非表示フィールドとして設定します。

ネストされたフォームを使用してノートを作成するときに設定し nested属性を持っているために十分であるべき
<%= note_form.hidden_field :nested %> 

未テスト。まだ

+11

この問題を添加することによって解決される:HAS_MANYするオプション、にhas_oneとbelongs_toのinverse_of。例えば、 http://www.daokaous.com/rails3.0.0_doc/classes/ActiveRecord/Associations/ClassMethods.html#M001988「双方向の関連付け」セクションの下に –

+2

次の場合に検証を無効にすることを選択しました:id == nil 。それは新しいネストされたレコードを書くときにだけ起こるべきなので、私はそれが安全であることを望んでいます。奇妙なことに、この問題は2.3.8に至っています。 – aceofspades

+3

inverse_ofは、レコードの親がまだ存在しない場合には動作していないようで、idをテストすることはできません。このネストされたハックが唯一の方法であるように見えます。 : – DGM

3

ライアンのソリューションは、実際には本当にクールです。 私は行って、コントローラを太くして、このネストが表示されないようにしました。主に私の意見は時々jsonなので、私はできるだけそこで逃げたいと思っています。

class Product < ActiveRecord::Base 
    has_many :notes 
    accepts_nested_attributes_for :note 
end 

class Note < ActiveRecord::Base 
    belongs_to :product 
    validates_presence_of :product_id unless :nested 
    attr_accessor :nested 
end 

class ProductController < ApplicationController 

def create 
    if params[:product][:note_attributes] 
     params[:product][:note_attributes].each { |attribute| 
      attribute.merge!({:nested => true}) 
    } 
    end 
    # all the regular create stuff here 
end 
end 
7

Rails3を使用している場合は、この文書を確認してください。レール3に

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#label-Validating+the+presence+of+a+parent+model

+2

非常に重要なポイントは、 "product_id"ではなく "product"の存在を検証することです。 – kuboon

+0

kuboonが正しい答えを持っていると思います。 "product_id"ではなく "product"ではなく、 "has_many:notes、inverse_of::product"への関連付けを変更する必要があります。 – quainjn

関連する問題