我有一个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。
提前致谢。
答案 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_one
和has_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