【问题标题】:How do I create a new object referencing an existing nested attribute?如何创建引用现有嵌套属性的新对象?
【发布时间】:2012-01-08 10:09:24
【问题描述】:

我有一个项目资源和一个所有者资源。

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

我的问题是我无法创建引用现有 Owner 对象的新 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 =&gt; "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。

提前致谢。

【问题讨论】:

    标签: ruby-on-rails nested-attributes


    【解决方案1】:

    我以另一种方式解决了这个问题,并想在此处发布它的简化版本,以防它对其他人有所帮助。在我的真实应用中,两个资源之间的关联是 HABTM,而嵌套资源是文件附件。

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

    然后我进一步将嵌套资源分为存在于数据库中的对象和不存在的对象,将存在的对象的 id 放入一个数组中。

    如果不存在现有的嵌套对象,那么从这里开始就一帆风顺了。

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

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

    然后您可以调用@item.save 并让它在出现任何错误时重新渲染视图。

    我仍然无法确定这是一个错误还是 Rails 的一个功能。如果有人对此主题或我的解决方案有任何想法,我会很高兴听到他们的意见。

    【讨论】:

    【解决方案2】:

    当您尝试使用嵌套属性中的所有者 ID 创建 Item 时,它会告诉 ActiveRecord 更新现有的 Owner 记录。 ActiveRecord 找不到 Owner 记录,因为没有现有的外键值(项目记录的 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 关联并将外键移至 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.
    

    【讨论】:

    • 谢谢!我已经一年多没有从事这个项目了,但你的回答是有道理的。有时间我会试试看(出于兴趣)。
    【解决方案3】:

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

    具体来说,您遇到的错误情况是因为它期望父级应该能够找到嵌套模型,给定嵌套模型的 id。即

    parent.nested_model.find(id)
    

    它似乎在那里,基本上停止更新不属于父级的子模型

    【讨论】:

    • 谢谢。我将示例更改为使用 has_one。不幸的是,问题仍然存在。有什么方法可以实现我正在尝试的目标,还是我最好还是回到绘图板上?
    • 不是真的,它适用于belongs_to,只是那里没有它的例子。如果 has_one 有效,belongs_to 也有效。
    • @RyanBigg 嗯,我一定误读了嵌套的工作原理。是的,如果 has_one 有效,belongs_to 应该有效。 @Jack 不,您发布的灯塔链接 (rails.lighthouseapp.com/projects/8994/tickets/…) 似乎是个问题。
    【解决方案4】:

    这就是我实现类似但并不完美的方法。看一看!虽然现在我的测试失败了很多,因为我不太了解工厂女孩。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-10
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      相关资源
      最近更新 更多