ActiveRecord, has_many:through и полиморфные ассоциации
Folks,
Хочу убедиться, что я правильно понимаю это. И, пожалуйста, не обращайте внимания на случай наследования здесь (SentientBeing), стараясь вместо этого сосредоточиться на полиморфных моделях в отношениях has_many:through. Тем не менее, рассмотрим следующее...
class Widget < ActiveRecord::Base
has_many :widget_groupings
has_many :people, :through => :widget_groupings, :source => :person, :conditions => "widget_groupings.grouper_type = 'Person'"
has_many :aliens, :through => :widget_groupings, :source => :alien, :conditions => "video_groupings.grouper_type = 'Alien'"
end
class Person < ActiveRecord::Base
has_many :widget_groupings, :as => grouper
has_many :widgets, :through => :widget_groupings
end
class Alien < ActiveRecord::Base
has_many :widget_groupings, :as => grouper
has_many :widgets, :through => :widget_groupings
end
class WidgetGrouping < ActiveRecord::Base
belongs_to :widget
belongs_to :grouper, :polymorphic => true
end
В идеальном мире я хотел бы, учитывая виджет и человека, сделать что-то вроде:
widget.people << my_person
Однако, когда я делаю это, я заметил, что "тип" "группировщика" всегда равен null в widget_groupings. Тем не менее, если я к чему-то вроде следующего:
widget.widget_groupings << WidgetGrouping.new({:widget => self, :person => my_person})
Тогда все работает, как я обычно ожидал. Я не думаю, что когда-либо видел, что это происходит с неполиморфными ассоциациями, и просто хотел узнать, было ли это что-то конкретное для этого варианта использования или я потенциально смотрю на ошибку.
Спасибо за любую помощь!
4 ответа
Существует известная проблема с Rails 3.1.1, которая нарушает эту функциональность. Если у вас возникла эта проблема, сначала попробуйте обновить, это было исправлено в 3.1.2
Ты так близко. Проблема в том, что вы неправильно используете параметр:source.: источник должен указывать на полиморфное отношение принадлежащие к. Затем все, что вам нужно сделать, это указать:source_type для отношения, которое вы пытаетесь определить.
Это исправление в модели виджетов должно позволить вам делать именно то, что вы ищете.
class Widget < ActiveRecord::Base
has_many :widget_groupings
has_many :people, :through => :widget_groupings, :source => :grouper, :source_type => 'Person'
has_many :aliens, :through => :widget_groupings, :source => :grouper, :source_type => 'Alien'
end
Как упоминалось выше, это не работает с rails 3.1.1 из-за ошибки в:source, но это исправлено в Rails 3.1.2
Например: иметь много , , , . Иtrains
,copters
,trucks
,ships
есть много .
Другойlocations
могут иметь аналогичные транспорты(хранить вmoveable
полиморфные колонки).
#db/migrations/create_moveable_locations.rb
class CreateMoveableLocations < ActiveRecord::Migration
def change
create_table :moveable_locations do |t|
t.references :moveable, polymorphic: true
t.references :location
t.timestamps
end
end
end
#app/models/moveable_location.rb
class MoveableLocation < ActiveRecord::Base
belongs_to :moveable, polymorphic: true
belongs_to :location
end
#app/models/location.rb
class Location < ActiveRecord::Base
has_many :moveable_locations, dependent: :destroy
has_many :trains, through: :moveable_locations, source: :moveable, source_type: 'Train'
has_many :copters, through: :moveable_locations, source: :moveable, source_type: 'Copter'
has_many :trucks, through: :moveable_locations, source: :moveable, source_type: 'Truck'
has_many :ships, through: :moveable_locations, source: :moveable, source_type: 'Ship'
end
#app/models/train.rb
class Train < ActiveRecord::Base
has_many :moveable_locations, as: :moveable, dependent: :destroy
has_many :locations, through: :moveable_locations
end
#app/models/copter.rb
class Copter < ActiveRecord::Base
has_many :moveable_locations, as: :moveable, dependent: :destroy
has_many :locations, through: :moveable_locations
end
#app/models/truck.rb
class Truck < ActiveRecord::Base
has_many :moveable_locations, as: :moveable, dependent: :destroy
has_many :locations, through: :moveable_locations
end
#app/models/ship.rb
class Ship < ActiveRecord::Base
has_many :moveable_locations, as: :moveable, dependent: :destroy
has_many :locations, through: :moveable_locations
end
С использованием:
train1 = Train.create(title: 'Train1')
train2 = Train.create(title: 'Train2')
location1 = Location.create(title: 'Location1', train_ids: [train1.id, train2.id])
location2 = Location.create(title: 'Location2', trains: [train1, train2])
location3 = Location.create(title: 'Location3')
location3.train_ids << [train1., train2.id]
location4 = Location.create(title: 'Location34')
location4.trains << [train1, train2]
copter1 = Copter.create(title: 'Copter1', location_ids: [location1.id, location2.id]
copter2 = Copter.create(title: 'Copter1')
copter2.location_ids << [location1.id, location2.id, location3.id]
Имеет много: сквозной и полиморфный не работают вместе. Если вы попытаетесь получить к ним доступ напрямую, это должно привести к ошибке. Если я не ошибаюсь, вы должны написать вручную widget.people и процедуру push.
Я не думаю, что это ошибка, это просто то, что еще не было реализовано. Я предполагаю, что мы видим это в функции, потому что у каждого есть случай, в котором они могли бы использовать это.