2012-08-03 51 views
8

ActiveRecord似乎並不理解,給定一組具有嵌套屬性的現有記錄的參數,它可以創建一個新的嵌套記錄,該記錄本身具有嵌套的現有記錄。 (關係樹:Existing -> New -> ExistingAcitveRecord不會爲具有嵌套現有記錄的新關聯記錄accept_nested_attributes_

這是一個錯誤,還是我錯過了什麼?

讓我給你看一個簡單的例子。

這裏是我的模型:

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 

我做了每個表中的一個記錄,因此它們有關的,所以每個表都有一個記錄在其與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),與一個新的Post相關。 它可以在我從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 2012-08-03 21:07:52

+0

哎呀,這個問題依然存在。 :)我會簡化這個例子。 – wulftone 2012-08-03 21:17:28

+0

長問題,但新記錄如何具有現有的關聯? – pjammer 2012-08-03 21:25:49

回答

4

以下是我認爲正在發生的事情:您正在爲組傳遞一個ID,指示ActiveRecord該組存在。 ActiveRecord正試圖找到該組以使用group_attributes中的其他數據對其進行更新。既然你這樣做是post_attributes,ActiveRecord的是試圖通過之間的關聯找到該組。也就是說,ActiveRecord首先查找關聯組 - 其中id = post.group_id - 然後從該結果中查找ID = 1的組織。對於父母關係來說,這看起來有點奇怪和笨拙,就像你的情況一樣。我相信你可以看到,在朝着另一個方向前進時這是有用的行爲,其中嵌套屬性表示一個或多個潛在的許多孩子。

但是,根據post_attributes中的數據創建的發佈對象尚未與組關聯 - post.group_id爲零。所以,當ActiveRecord首先進行搜索以獲取關聯組時,它就會變空。相應地,它在(空)結果中找不到ID = 1的組。從技術上講,該記錄在那裏,但在之後,它不存在

您可以通過在post_attributes中包含group_id => 1來證明這一點。我相信如果你這樣做,ActiveRecord將通過關聯找到組,然後從結果中成功選擇ID = 1的組,然後使用group_attributes中的其他數據更新該組。

還要注意的是,只有原因包括嵌套屬性的組內後,就像你正在做的是,如果你是允許用戶在創建一個新的職位的同時更新組名。如果您所要做的只是將新帖子鏈接到現有的羣組,那麼您只需要在post_attributes中包含group_id,並且可以擺脫group_attributes。

+0

這對我來說似乎很合理,但這種情況早已消失。 :)我確實記得我_did_想同時更新關聯和根記錄上的屬性(我沒有使用這些確切的User,Post和Group表,但它是一個類似的結構)。我認爲做這樣一個行動的必要性被放在了未來實施的後面,然後被遺忘了。它可能會回來困擾我們!感謝您的回答。當我再次遇到這個問題時,我一定會參考它。 – wulftone 2013-11-14 20:37:55

+0

再試一次,即使我在Post中有一個'group_id',我也會創建新的'Groups' - 儘管它不會引發錯誤。它只是忽略'group_id'並且創建一個。仍然似乎不可能做到。 – wulftone 2013-11-14 21:24:02

+0

該死的。真的以爲我有那個釘子。我會花一些時間在本週末討論這個場景,看看我能想出什麼,現在它一直停留在我身上。 ;) – Yardboy 2013-11-15 14:08:15