Подтвердить что ты не робот

Rails: has_many through with polymorphic association - будет ли это работать?

A 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

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

4b9b3361

Ответ 1

Вам нужно сделать:

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 meals
p.meals.each do |m|
  puts m
end

# get a person 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

Ответ 2

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

Вот метод 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 может быть очень полезен, если вам необходимо переопределить поведение рельсов по умолчанию)

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