class Patient < ApplicationRecord
has_many :sites_siteables, as: :siteable
has_many :sites, through: :sites_siteables
end
class Provider < ApplicationRecord
has_many :sites_siteables, as: :siteable
has_many :sites, through: :sites_siteables
end
# this is the join model between Site and Siteable(which is any model)
# you can generate this model by running the command:
# rails g model sites_siteable site:belongs_to siteable:references{polymorphic}
class SitesSiteable < ApplicationRecord
belongs_to :site
belongs_to :siteable, polymorphic: true
end
class Site < ApplicationRecord
has_many :sites_siteables
has_many :patients, through: :sites_siteables, source: :siteable, source_type: 'Patient'
has_many :providers, through: :sites_siteables, source: :siteable, source_type: 'Provider'
end
Использование
Patient.first.sites
# => returns Sites
Provider.first.sites
# => returns Sites
Site.first.patients
# => returns Patients
Site.first.providers
# => returns Providers
Комментарии
вышеуказанный код: Site
has_many :patients
, has_many :providers
, has_many :users
и т. Д.... требуется, и вы не можете просто собрать их вместе как один has_many
;то есть вы не можете сделать следующее (это приведет к ошибке):
# app/models/site.rb
has_many :siteables, through: :sites_siteables, source: :siteable
... потому что если это произойдет, скажем, у вас есть Site.first.siteables
, то значение возвращаетсябудет коллекцией разных видов моделей: то есть:
Site.first.siteables[0] # => returns Provider
Site.first.siteables[1] # => returns Provider
Site.first.siteables[2] # => returns Patient
... и это проблематично, потому что нет единой модели для представления запроса по этому вопросу, и я думаю, что она не совместима с кодом Rails:то есть почему следующее сбивает с толку (по крайней мере, на стороне генерации SQL-строки):
Site.first.siteables.where(phone_number: '123456')
... и, вероятно, именно поэтому Rails специально не разрешает и вызывает ошибку (при полиморфной ассоциации), и что вы должны указать, тогда source_type
:
has_many :siteables, through: :sites_siteables, source: :siteable
Однако ...
Если вы действительно намереваетесь не иметь так много строк has_many
вSite
модель, подобная следующей:
has_many :patients, through: :sites_siteables, source: :siteable, source_type: 'Patient'
has_many :providers, through: :sites_siteables, source: :siteable, source_type: 'Provider'
has_many :users, through: :sites_siteables, source: :siteable, source_type: 'User'
# ...
# ...
... вы можете создать другую "Абстрактную" таблицу / модель для представления полиморфной записи (я обновлю ответ, если вы хотите, дайте мне знать).то есть вместо этого вы можете сделать что-то вроде следующего:
Site.first.abstract_siteables[0].siteable
# => returns a Patient, or a Provider, or a User, etc...
Site.first.abstract_siteables[1].siteable
# => returns a Patient, or a Provider, or a User, etc...
Site.first.abstract_siteables[2].siteable
# => returns a Patient, or a Provider, or a User, etc...