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.

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

Другие вопросы по тегам