¿Cómo funciona has_one:through?
-
01-07-2019 - |
Pregunta
Tengo tres modelos:
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
El problema es que, durante la ejecución, si agrego un paquete a un elemento de lanzamiento, no se da cuenta de que el paquete es un paquete.Por ejemplo:
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
>>
Parece que debería tener acceso a item.pack, pero no sé que el paquete es un elemento del paquete.
Solución
Parece que su uso de has_one :through es correcto.El problema que estás viendo tiene que ver con guardar objetos.Para que una asociación funcione, el objeto al que se hace referencia debe tener una identificación para completar el model_id
campo para el objeto.En este caso, PackReleaseItems
tener un pack_id
y un release_item_id
campo que debe completarse para que la asociación funcione correctamente.Intente guardar antes de acceder a los objetos a través de una asociación.
Otros consejos
Tu problema está en cómo estás asociando el ReleaseItem
y el Pack
.
has_many :through
y has_one :through
ambos funcionan a través de un objeto que también actúa como una tabla de unión, en este caso PackReleaseItem
.Dado que esta no es solo una tabla de unión (si lo fuera, deberías usar has_many
sin :through
), para crear correctamente la asociación es necesario crear el objeto de unión, así:
>> item.pack_release_items.create :pack => pack
¿Qué estás haciendo con tu item.pack = pack
La llamada es simplemente asociar los objetos en la memoria.Cuando vas a buscarlo de nuevo, parece "through
" el pack_release_items
, que está vacío.
Desea guardar o crear (en lugar de crear uno nuevo) el artículo y el paquete.De lo contrario, la base de datos no ha asignado identificaciones para la asociación.