Rails: has_many through с полиморфной ассоциацией - это сработает?

У Person может быть много Events, и у каждого Event может быть одна полиморфная Eventable запись. Как указать взаимосвязь между записью Person и Eventable?

Вот модели, которые у меня есть:

class Event < ActiveRecord::Base
  belongs_to :person
  belongs_to :eventable, :polymorphic => true
end

class Meal < ActiveRecord::Base
  has_one :event, :as => eventable
end

class Workout < ActiveRecord::Base
  has_one :event, :as => eventable
end

Главный вопрос касается класса Person:

class Person < ActiveRecord::Base
  has_many :events
  has_many :eventables, :through => :events  # is this correct???
end

Могу ли я сказать has_many :eventables, :through => :events, как я сделал выше?

Или я должен их все изложить так:

has_many :meals, :through => :events
has_many :workouts, :through => :events

Если вы видите более простой способ выполнить то, что мне нужно, я все уши! :-)


person Finch    schedule 09.08.2011    source источник
comment
+1 за вопрос без 75 строк кода, относящийся только к вашему конкретному проекту.   -  person    schedule 06.06.2012


Ответы (2)


Ты должен сделать:

class Person < ActiveRecord::Base
  has_many :events
  has_many :meals, :through => :events, :source => :eventable,
    :source_type => "Meal"
  has_many :workouts, :through => :events, :source => :eventable,
    :source_type => "Workout"
end

Это позволит вам сделать это:

p = Person.find(1)

# get a person's meals
p.meals.each do |m|
  puts m
end

# get a person's workouts
p.workouts.each do |w|
  puts w
end

# get all types of events for the person
p.events.each do |e|
  puts e.eventable
end
person Rob Sobers    schedule 09.08.2011

Другой вариант - использовать шаблон наследования одной таблицы (STI) или наследования нескольких таблиц (MTI), но для этого требуется некоторая переработка таблиц ActiveRecord / DB, но это может помочь другим найти это, кто разрабатывает его впервые.

Вот метод STI в Rails 3+: ваша концепция Eventable становится классом и нуждается в столбце type (который автоматически заполняется направляющими).

class Eventable < ActiveRecord::Base
  has_one :event
end

Затем ваши два других класса наследуют от Eventable вместо AR :: Base

class Meal < Eventable
end

class Workout < Eventable
end

И ваш объект события в основном такой же, только не полиморфный:

class Event < ActiveRecord::Base
  belongs_to :person
  belongs_to :eventable
end

Это может сделать некоторые из ваших других слоев более запутанными, если вы никогда не видели этого раньше и не будете осторожны. Например, к одному объекту Meal можно получить доступ через /meals/1 и /eventable/1, если вы сделаете обе конечные точки доступными в маршрутах, и вам нужно знать, какой класс вы используете, когда вы извлекаете унаследованный объект (подсказка: becomes метод может быть очень полезным, если вам нужно изменить поведение направляющих по умолчанию)

Но, по моему опыту, это гораздо более четкое разграничение обязанностей по мере масштабирования приложений. Просто образец для рассмотрения.

person toobulkeh    schedule 28.03.2016
comment
Хотя STI может быть полезен в некоторых ситуациях, я думаю, что было бы немного самонадеянно предполагать, что это было бы правильным решением здесь, и это умаляет цель вопроса - существует множество очень веских причин для использования полиморфных ассоциаций для моделей, которые нет смысла иметь в одной таблице! - person nightpool; 03.03.2021
comment
Я не предполагал - я просто предлагал другой вариант. - person toobulkeh; 10.03.2021