Много ко многим полиморфным? - PullRequest
0 голосов
/ 11 июня 2018

В моем приложении много «Сайтов», и у меня есть несколько типов пользователей, таких как «Пациент», «Поставщик», «Медсестра», «Администратор» и т. Д.

class Patient
  has_many :sites
end

class Provider
  has_many :sites
end

#etc user models...

class Site < ApplicationRecord
  # I don't want to have to name every user model here...
  has_many :patients
  has_many :providers
  has_many :nurses
  # etc. user models...
end

Что яхотел бы сделать, есть ли так, что у каждого типа пользователя может быть много сайтов, и у каждого сайта может быть много каждого типа пользователя, , но я не хочу делать следующее, потому что модели типов пользователей могут увеличиваться в геометрической прогрессии...

Я подумал, что, может быть, я смогу создать полиморфные отношения, но это не удовлетворяет отношению many_to_many.

Ответы [ 2 ]

0 голосов
/ 11 июня 2018
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...
0 голосов
/ 11 июня 2018

вы, вероятно, захотите использовать наследование одной таблицы:

http://edgeguides.rubyonrails.org/association_basics.html#single-table-inheritance

тогда ваши пациенты, поставщики, медсестры и т. Д. Все будут наследовать от базового класса, называемого SiteOwner или аналогичным, который будет единственной ассоциацией в классе Site.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...