【问题标题】:How does has_one :through work?has_one :through 是如何工作的?
【发布时间】:2010-09-10 12:48:59
【问题描述】:

我有三个模型:

class ReleaseItem < ActiveRecord::Base
  has_many :pack_release_items
  has_one :pack, :through => :pack_release_items
end

class Pack < ActiveRecord::Base
  has_many :pack_release_items
  has_many :release_items, :through=>:pack_release_items
end

class PackReleaseItem < ActiveRecord::Base
  belongs_to :pack
  belongs_to :release_item
end

问题是,在执行过程中,如果我将一个包添加到 release_item,它不会知道该包是一个包。例如:

Loading development environment (Rails 2.1.0)
>> item = ReleaseItem.new(:filename=>'MAESTRO.TXT')
=> #<ReleaseItem id: nil, filename: "MAESTRO.TXT", created_by: nil, title: nil, sauce_author: nil, sauce_group: nil, sauce_comment: nil, filedate: nil, filesize: nil, created_at: nil, updated_at: nil, content: nil>
>> pack = Pack.new(:filename=>'legion01.zip', :year=>1998)
=> #<Pack id: nil, filename: "legion01.zip", created_by: nil, filesize: nil, items: nil, year: 1998, month: nil, filedate: nil, created_at: nil, updated_at: nil>
>> item.pack = pack
=> #<Pack id: nil, filename: "legion01.zip", created_by: nil, filesize: nil, items: nil, year: 1998, month: nil, filedate: nil, created_at: nil, updated_at: nil>
>> item.pack.filename
NoMethodError: undefined method `filename' for #<Class:0x2196318>
    from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/base.rb:1667:in `method_missing_without_paginate'
    from /usr/local/lib/ruby/gems/1.8/gems/mislav-will_paginate-2.3.3/lib/will_paginate/finder.rb:164:in `method_missing'
    from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/associations/association_collection.rb:285:in `send'
    from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/associations/association_collection.rb:285:in `method_missing_without_paginate'
    from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/base.rb:1852:in `with_scope'
    from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/associations/association_proxy.rb:168:in `send'
    from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/associations/association_proxy.rb:168:in `with_scope'
    from /usr/local/lib/ruby/gems/1.8/gems/activerecord-2.1.0/lib/active_record/associations/association_collection.rb:281:in `method_missing_without_paginate'
    from /usr/local/lib/ruby/gems/1.8/gems/mislav-will_paginate-2.3.3/lib/will_paginate/finder.rb:164:in `method_missing'
    from (irb):5
>> 

似乎我应该可以访问 item.pack,但它不知道该包是一个包项。

【问题讨论】:

    标签: ruby-on-rails ruby activerecord


    【解决方案1】:

    看来您对 has_one :through 的使用是正确的。您看到的问题与保存对象有关。要使关联起作用,被引用的对象需要有一个 id 来填充对象的 model_id 字段。在这种情况下,PackReleaseItems 有一个 pack_id 和一个 release_item_id 字段,需要填写这些字段才能使关联正常工作。在通过关联访问对象之前尝试保存。

    【讨论】:

    • 但如果我使用 has_many :through、belongs_to 或 has_one,我不必先保存。
    • 是的,这似乎已经解决了。不过,我认为我不必与其他协会这样做。
    • 这能解决吗?您可以发布交互式控制台会话的剪辑吗?我使用 Rails 2.1.0 做了一个小测试应用程序,甚至事先保存也无济于事,这就是我提交答案的原因。
    • 确实如此。我将在今晚或明天早上发布输出(我在工作中做 .NET 开发)。
    【解决方案2】:

    您的问题在于如何关联 ReleaseItemPack

    has_many :throughhas_one :through 都通过一个也充当连接表的对象工作,在本例中为PackReleaseItem。由于这不仅仅是一个连接表(如果是,你应该只使用has_many 而不使用:through),正确创建关联需要创建连接对象,如下所示:

    >> item.pack_release_items.create :pack => pack
    

    您对item.pack = pack 调用所做的只是将内存中的对象关联起来。当你再去查找它时,它看起来是“throughpack_release_items,它是空的。

    【讨论】:

    • >> item.pack_release_items.create :pack => pack => # >> item.pack => nil
    • 这可能是因为包没有满足所有的验证者。我回家后会再试一次。
    • Pack 在您的示例中为 nil,因为 Pack 尚未保存 - 您可以在 PackReleaseItem 中看到“pack_id: nil”。
    【解决方案3】:

    您想保存或创建(而不是新建)项目和包装。否则,数据库没有为关联分配 id。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-03
      相关资源
      最近更新 更多