ActiveRecord, has_many: through, dan Polymorphic Associations

117

Orang-orang,

Ingin memastikan saya memahami ini dengan benar. Dan tolong abaikan kasus untuk warisan di sini (SentientBeing), mencoba untuk fokus pada model polimorfik dalam has_many: melalui hubungan. Karena itu, pertimbangkan yang berikut ...

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :person, :conditions => "widget_groupings.grouper_type = 'Person'"
  has_many :aliens, :through => :widget_groupings, :source => :alien, :conditions => "video_groupings.grouper_type = 'Alien'"
end

class Person < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings
end

class Alien < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings  
end

class WidgetGrouping < ActiveRecord::Base
  belongs_to :widget
  belongs_to :grouper, :polymorphic => true
end

Di dunia yang sempurna, saya ingin, dengan Widget dan Orang, melakukan sesuatu seperti:

widget.people << my_person

Namun, ketika saya melakukan ini, saya perhatikan 'type' dari 'grouper' selalu null di widget_groupings. Namun, jika saya ke sesuatu seperti berikut:

widget.widget_groupings << WidgetGrouping.new({:widget => self, :person => my_person}) 

Kemudian semua bekerja seperti yang biasanya saya harapkan. Saya rasa saya belum pernah melihat ini terjadi dengan asosiasi non polimorfik dan hanya ingin tahu apakah ini adalah sesuatu yang spesifik untuk kasus penggunaan ini atau apakah saya berpotensi melihat bug.

Terima kasih atas bantuannya!

Cory
sumber

Jawaban:

162

Ada masalah umum dengan Rails 3.1.1 yang merusak fungsionalitas ini. Jika Anda mengalami masalah ini, coba perbarui dulu, ini telah diperbaiki di 3.1.2

Anda sangat dekat. Masalahnya adalah Anda menyalahgunakan opsi: sumber. : source harus menunjuk ke hubungan polimorfik milik_to. Kemudian yang perlu Anda lakukan adalah menentukan: source_type untuk hubungan yang Anda coba tentukan.

Perbaikan model Widget ini memungkinkan Anda melakukan apa yang Anda cari.

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :grouper, :source_type => 'Person'
  has_many :aliens, :through => :widget_groupings, :source => :grouper, :source_type => 'Alien'
end
EmFi
sumber
Ya Tuhan, itu sangat jelas menyakitkan. Aku tidak percaya aku melihatnya. Terima kasih EmFi!
Cory
Tidak masalah, saya rasa saya menderita sekitar satu hari tentang bagaimana melakukan ini pertama kali saya menemukannya. Tidak membantu bahwa itu adalah salah satu hal pertama yang saya coba lakukan di Rails yang tidak melibatkan mengikuti tutorial / buku.
EmFi
1
Seperti yang ditunjukkan oleh scotkf, ada regresi di ActiveRecord 3.1.1 yang memblokir perilaku ini. Mengupgrade ke 3.1.2 akan memungkinkan solusi ini berfungsi.
EmFi
6
Sama seperti yang disebutkan @Shtirlic. Apakah ada cara untuk tidak menentukan source_type, sehingga Anda memiliki hasil yang beragam? Jika ada yang memecahkan ini, ingin tahu caranya.
Damon Aw
3
Masih berfungsi pada Rails 4.2.0. Namun, apakah ada cara untuk melakukannya hari ini tanpa source_type dan dua asosiasi terpisah?
Emeka
3

Seperti disebutkan di atas, ini tidak berfungsi dengan rails 3.1.1 karena bug di: source, tetapi diperbaiki di Rails 3.1.2

scottkf.dll
sumber
-4

memiliki banyak: melalui dan polimorfik tidak bekerja sama. Jika Anda mencoba mengaksesnya secara langsung, itu akan menimbulkan kesalahan. Jika saya tidak salah, Anda harus menulis widget.people secara manual dan rutinitas push.

Menurut saya ini bukan bug, ini hanya sesuatu yang belum diimplementasikan. Saya membayangkan kami melihatnya di fitur, karena setiap orang memiliki casing di mana mereka dapat menggunakannya.

cgr
sumber
6
Mereka bekerja sama. Misalnya: has_many: subscription,: as =>: subscriber has_many: subscriber
,:
Saya akan memberikan contoh kode gagal saya sebagai posting terpisah dalam waktu dekat :) Ini akan menyelamatkan saya dari banyak sakit kepala untuk mencari cara bagaimana melewati kesalahan itu.
cgr