如何创建引用现有嵌套属性的新对象?

时间:2012-01-08 10:09:25

标签: ruby-on-rails nested-attributes

我有一个Item资源和一个Owner资源。

rails g scaffold Item name:string
rails g scaffold Owner name:string

class Item < ActiveRecord::Base
  has_one :owner
  accepts_nested_attributes_for :owner
end

class Owner < ActiveRecord::Base
  belongs_to :item
end

我的问题是我无法创建引用现有所有者对象的新Item对象。

In /db/migrate/create_owners.rb
def self.up
  ...
  t.integer :item_id
end

rake db:migrate   
rails c

ruby-1.9.2-p0 > o= Owner.create(:name => "Test")
 => #<Owner id: 1, name: "Test", created_at: "...", updated_at: "...">

ruby-1.9.2-p0 > i= Item.create(:owner_attributes => {"id" => Owner.last.id.to_s})
ActiveRecord::RecordNotFound: Couldn't find Owner with ID=1 for Item with ID=

我知道Item.create(:owner_id => "1")在这种情况下会起作用,但不幸的是,这在我的应用中不是一个可行的解决方案。这是因为我正在动态添加和删除嵌套属性,例如,需要使用一个现有的Owner对象和一个新的Owner对象创建一个新的Item对象。

我找到了这些链接,但如果这是rails中的功能或错误,则无法解决问题:
https://rails.lighthouseapp.com/projects/8994/tickets/4254-assigning-nested-attributes-fails-for-new-object-when-id-is-specified
http://osdir.com/ml/RubyonRails:Core/2011-05/msg00001.html

有人可以告诉我如何使这项工作或我误解了使用'accepts_nested_attributes_for'的正确方法吗?

我使用的是Rails 3.0.5和Ruby 1.9.2p0。

提前致谢。

4 个答案:

答案 0 :(得分:3)

我以另一种方式解决了问题,并希望在此处发布简化版本,以防它帮助其他任何人。在我的真实应用程序中,两个资源之间的协作是HABTM,嵌套资源是文件附件。

因此,在控制器的create动作中,我将原始资源的参数与嵌套资源的参数分开。

然后我进一步将嵌套资源分成数据库中存在的对象和不存在的对象,将那些数据的ID放入数组中。

如果没有现有的嵌套对象,那么它就从这里开始了。

但是,假设存在现有和新的嵌套对象,我创建了一个新的Item对象:
@item = Item.new(:attachment_ids => existing_attachment_ids)

之后我更新@item:
@item.update_attributes(original_item_params)
@item.update_attributes(params_for_new_nested_objects)

然后,您可以调用@item.save并在发生任何错误时重新呈现视图。

如果这是一个bug或Rails功能,我仍然无法解决。如果有人对这个问题或我的解决方案有任何想法,我会很高兴听到它们。

答案 1 :(得分:1)

当您尝试在嵌套属性中创建具有所有者ID的Item时,它会告诉ActiveRecord更新现有的Owner记录。 ActiveRecord找不到所有者记录,因为没有现有的外键值(项目记录的ID仍为零)。

Item.create(:owner_attributes => {"id" => Owner.last.id.to_s})
#=> ActiveRecord::RecordNotFound: Couldn't find Owner with ID=1 for Item with ID=

尝试交换has_one / belongs_to associtaions并将外键移动到items表。然后,您可以在父(非嵌套)模型中设置外键,并仍然使用嵌套属性。

class Item < ActiveRecord::Base
  belongs_to :owner
  accepts_nested_attributes_for :owner
end

class Owner < ActiveRecord::Base
  has_one :item
end

owner = Owner.create

Item.create(:owner_id => owner.id, :owner_attributes => {"id" => owner.id, ...})  
#=> Works!!! Note that the owner id is used twice. With some work you could probably set the id in one place or the other.

答案 2 :(得分:0)

accepts_nested_attributes_for仅用于has_onehas_many关联。 (参见http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html no belongs_to)它被称为'嵌套',因此没有多少帮助。也许重构你的应用程序?

具体而言,您遇到的错误情况是因为在给定嵌套模型的id的情况下,它期望Parent应该能够找到嵌套模型。即。

parent.nested_model.find(id)

它似乎在那里,基本上停止更新不属于父

的子模型

答案 3 :(得分:0)

这就是我取得类似成就的方式,但并不完美。看一看!我现在的测试失败很多,因为我不太了解Factory Girl。

creating an object with has_many association results in item can not be blank

相关问题