has_one:through如何工作?

时间:2020-03-06 14:19:55  来源:igfitidea点击:

我有三种模式:

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,但是并没有意识到该包是Pack项。

解决方案

看来我们对has_one:through的使用是正确的。我们看到的问题与保存对象有关。为了使关联正常工作,被引用的对象需要具有一个ID,以填充该对象的" model_id"字段。在这种情况下," PackReleaseItems"具有" pack_id"和" release_item_id"字段,需要填写这些字段以使关联正常工作。通过关联访问对象之前,请尝试保存。

问题在于如何关联ReleaseItemPack

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

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

我们使用item.pack = pack调用所做的只是将内存中的对象关联起来。当我们再次查找它时,它看起来像"通过"" pack_release_items",它是空的。

我们要保存或者创建(而不是新建)项目和包装。否则,数据库未为关联分配ID。