Rails: has_many с полиморфной ассоциацией - это будет работать? - PullRequest
39 голосов
/ 09 августа 2011

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

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

Ответы [ 2 ]

69 голосов
/ 09 августа 2011

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

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
1 голос
/ 28 марта 2016

Другим вариантом этого является использование шаблона наследования одной таблицы (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 метод может быть очень полезен, если вам нужно переопределить поведение рельсов по умолчанию)

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

...