2012-08-03 5 views
8

ActiveRecordはネストされた属性を持つ既存のレコードのパラメータセットを受け取ると、ネストされた新しいレコードを作成できます。既存のレコードです。 (関係ツリー:Existing -> New -> ExistingAcitveRecordはネストされた既存のレコードを持つ新しい関連レコードを受け入れません。

これはバグですか、それとも不足していますか?

簡単な例を示しましょう。ここで

は私のモデルです:

class User < ActiveRecord::Base 
    has_many :posts 
    attr_accessible :name, :posts_attributes 
    accepts_nested_attributes_for :posts 
end 

class Post < ActiveRecord::Base 
    belongs_to :group 
    belongs_to :user 
    attr_accessible :content, :title, :group_attributes 
    accepts_nested_attributes_for :group 
end 

class Group < ActiveRecord::Base 
    has_many :posts 
    attr_accessible :name 
end 

私は各テーブルに1つのレコードを作って、それに応じて関連するので、各テーブルにはid=1 - このとその中のレコードが知られていました。私は既存のユーザー、新しいポスト、および既存のグループを持っている、とaccepts_nested_attributes_forを使用して、そのレコードを更新しようとした場合さて、それはそれを好きではない:

1.9.3-p125 :044 > params 
{ 
        :id => 1, 
       :name => "Billy", 
    :posts_attributes => [ 
     [0] { 
          :title => "Title", 
         :content => "Some magnificent content for you!", 
      :group_attributes => { 
        :id => 1, 
       :name => "Group 1" 
      } 
     } 
    ] 
} 
1.9.3-p125 :045 > u 
#<User:0x00000002f7f380> { 
      :id => 1, 
      :name => "Billy", 
    :created_at => Fri, 03 Aug 2012 20:21:37 UTC +00:00, 
    :updated_at => Fri, 03 Aug 2012 20:21:37 UTC +00:00 
} 
1.9.3-p125 :046 > u.update_attributes params 
    (0.1ms) begin transaction 
    (0.1ms) rollback transaction 
ActiveRecord::RecordNotFound: Couldn't find Group with ID=1 for Post with ID= 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:462:in `raise_nested_attributes_record_not_found' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:332:in `assign_nested_attributes_for_one_to_one_association' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:288:in `group_attributes=' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:94:in `block in assign_attributes' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:93:in `each' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:93:in `assign_attributes' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/base.rb:498:in `initialize' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/reflection.rb:183:in `new' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/reflection.rb:183:in `build_association' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/associations/association.rb:233:in `build_record' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/associations/collection_association.rb:112:in `build' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:405:in `block in assign_nested_attributes_for_collection_association' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:400:in `each' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:400:in `assign_nested_attributes_for_collection_association' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/nested_attributes.rb:288:in `posts_attributes=' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:85:in `block in assign_attributes' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:78:in `each' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/attribute_assignment.rb:78:in `assign_attributes' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/persistence.rb:216:in `block in update_attributes' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/transactions.rb:208:in `transaction' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/transactions.rb:293:in `with_transaction_returning_status' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.7/lib/active_record/persistence.rb:215:in `update_attributes' 
    from (irb):15 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.7/lib/rails/commands/console.rb:47:in `start' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.7/lib/rails/commands/console.rb:8:in `start' 
    from /home/trevor/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.7/lib/rails/commands.rb:41:in `<top (required)>' 
    from script/rails:6:in `require' 
    from script/rails:6:in `<main>'1.9.3-p125 :047 > 

それがグループを見つけることができないと考えて(既知のIDを持つ)、新しい投稿に関連しています。 group_attributesからIDを削除すると機能します(ただし、新しいグループレコードが作成されます)。 私はposts_attributesにIDを与え、group_attributesからIDを削除して(そして再び新しいグループを作成すると)動作します。 IDがすべてある場合にも機能します。

関係が働いている:

1.9.3-p125 :059 > p = Post.new({ group_attributes: { name: 'Testing' } }) 
#<Post:0x00000004212380> { 
      :id => nil, 
     :title => nil, 
     :content => nil, 
     :group_id => nil, 
     :user_id => nil, 
    :created_at => nil, 
    :updated_at => nil 
} 
1.9.3-p125 :060 > p.group 
[ 
    [0] #<Group:0x00000004211868> { 
       :id => nil, 
       :name => "Testing", 
     :created_at => nil, 
     :updated_at => nil 
    } 
] 

User作成中posts_attributesgroup_attributesを使用する際にすべてのレコードが新規であればそれはまた完全に動作します。

最初の例ではまだ動作しませんか? ActiveRecordはこれを理解するのに十分スマートでなければなりません...!

+0

ユーザモデルに 'has_many:comments'がありません。 – jordanpg

+0

おっと、問題は依然として立っています。私はこの例を単純化します。 – wulftone

+0

長い質問ですが、新しいレコードにはどのように既存の関連がありますか? – pjammer

答えて

4

これは私が起こっていると思います:グループのIDを渡して、グループが存在することをActiveRecordに示しています。 ActiveRecordはそのグループを見つけようとしていて、他のデータでグループを更新しようとしています。group_attributesです。あなたはこの内部post_attributesを行っているので、ActiveRecordのはポストグループ間の関連性を経由して、そのグループを見つけようとしています。つまり、ActiveRecordはまず関連グループ(id = post.group_id)を検索し、その結果からID = 1のグループを探します。これはあなたの場合のように、親関係のためにちょっと変わったと思われるかもしれませんがネストされた属性が1つ以上の潜在的に多くの子を表す、他の方向に向かうときにこれが役に立つ動作であることがわかります。

ただし、post_attributesのデータから作成された投稿オブジェクトはまだグループに関連付けられていません。post.group_idはnilです。したがって、ActiveRecordが最初に検索して関連付けられたグループを取得すると、そのグループは空になります。対応して、(空の)結果にID = 1のグループは見つかりません。技術的には、記録はそこにありますが、投稿との関連でははありません。

post_attributesにgroup_id => 1を含めることで、これを証明できます。私はあなたがそうするならば、ActiveRecordは関連によってグループを見つけて、結果からID = 1のグループをサブクラスで選択してから、そのグループをgroup_attributesの追加データで更新すると信じています。

あなたがやっているようにグループ内のネストされた属性を含める理由は、ユーザーが新しい投稿を作成するのと同時にグループ名を更新できるようにすることだけです。新しい投稿を既存のグループにリンクするだけの場合は、post_attributesにgroup_idを含めるだけで、group_attributesを取り除くことができます。

+0

これはかなり論理的だと思われますが、このシナリオは長く続いています。 :)私はアソシエーションとルートレコードの属性を同時に更新することを覚えています(これらのユーザー、ポスト、グループの正確な表は使用していませんでしたが、同様の構造です)。私はそのような行動を取る必要が、将来の実施のためにバックバーナーに置かれ、それから忘れ去られたと信じています。それは私たちに遭遇するために戻ってくるかもしれません!ご回答有難うございます。私がこれに再びぶつかるとき、私はそれを参照することを確かめるでしょう。 – wulftone

+0

もう一度やり直すと、 'Post'に' group_id'があっても新しい 'Groups'が作成されますが、エラーは出ません。とにかく 'group_id'を無視して、それを作成します。まだできないようです。 – wulftone

+0

Dammit。本当に私はそれを釘付けにしたと思った。私はこの週末のシナリオで遊んでいく時間を取って、何が出てくるのか見てみましょう。 ;) – Yardboy