ActiveRecord, has_many: through та Polymorphic Association


117

Люди,

Хочете переконатися, що я правильно це розумію. І, будь ласка, ігноруйте випадок спадкування тут (SentientBeing), намагаючись замість цього зосередити увагу на поліморфних моделях у has_many: через відносини. Однак, врахуйте наступне ...

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

Однак, коли я це роблю, я помітив, що "тип" групи "завжди є нульовим у віджетах. Однак, якщо я щось подібне:

widget.widget_groupings << WidgetGrouping.new({:widget => self, :person => my_person}) 

Тоді все працює так, як я б зазвичай очікував. Я не думаю, що я коли-небудь бачив, як це відбувається з неполіморфними асоціаціями, і я просто хотів дізнатися, чи це щось специфічне для цього випадку використання чи я потенційно дивлюся на помилку.

Дякуємо за будь-яку допомогу!

Відповіді:


162

Існує відома проблема з Rails 3.1.1, яка порушує цю функціональність. Якщо у вас виникла ця проблема, спершу спробуйте оновити, вона була виправлена ​​в 3.1.2

Ти так близько. Проблема полягає в тому, що ви зловживаєте параметром: source. : джерело повинно вказувати на поліморфні відносини last_to. Тоді все, що вам потрібно зробити, це вказати: 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

О, мій боже, що так болісно очевидно, що я не можу повірити, що я засклений прямо над цим. Дякую EmFi!
Кори

Немає проблем, я думаю, що я агонізував близько дня, як це зробити вперше, коли зіткнувся з цим. Не допомогло, що це було одне з перших речей, які я намагався зробити в Rails, і це не стосувалося підручника / книги.
EmFi

1
Як вказує scotkf, в ActiveRecord 3.1.1 спостерігається регресія, яка блокує таку поведінку. Оновлення до 3.1.2 дозволить це рішення працювати.
EmFi

6
Те саме, що згадував @Shtirlic. Чи є спосіб не вказати source_type, щоб у вас був змішаний набір результатів? Якщо хтось вирішив це, дуже хотів би знати, як.
Damon Aw

3
Досі працює з Rails 4.2.0. Однак чи є спосіб досягти цього в наші дні без source_type та двох окремих асоціацій?
Емека

3

Як було сказано вище, це не працює з рейками 3.1.1 через помилку на: source, але це виправлено в Rails 3.1.2


-4

Є багато: наскрізний і поліморфний не працюють разом. Якщо ви спробуєте отримати доступ до них безпосередньо, це має призвести до помилки. Якщо я не помиляюся, вам доведеться вручну написати widget.people і поштовх.

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


6
Вони працюють разом. Наприклад: has_many: підписки,: as =>: підписується has_many: передплатники
,:

Я наведу приклад свого невдалого коду як окремий пост найближчим часом :) Це врятувало б мені багато головного болю, щоб зрозуміти, як обійти цю помилку.
cgr
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.