Как работает has_one :through?
-
01-07-2019 - |
Вопрос
У меня три модели:
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 правильно.Проблема, которую вы видите, связана с сохранением объектов.Чтобы ассоциация работала, объект, на который ссылается, должен иметь идентификатор для заполнения model_id
поле для объекта.В этом случае, PackReleaseItems
иметь pack_id
и release_item_id
поле, которое необходимо заполнить для корректной работы ассоциации.Попробуйте сохранить перед доступом к объектам через ассоциацию.
Другие советы
Ваша проблема в том, как вы связываете ReleaseItem
и Pack
.
has_many :through
и has_one :through
оба работают через объект, который также действует как таблица соединений, в данном случае PackReleaseItem
.Поскольку это не просто таблица соединений (если бы это было так, вам следует просто использовать has_many
без :through
), правильное создание ассоциации требует создания объекта соединения, например:
>> item.pack_release_items.create :pack => pack
Что ты делаешь со своим item.pack = pack
вызов просто связывает объекты в памяти.Когда вы снова посмотрите на это, оно выглядит "through
" pack_release_items
, который пуст.
Вы хотите сохранить или создать (а не создать новый) предмет и упаковать его.В противном случае база данных не присвоила идентификатор ассоциации.