Rails несколько отношений has_many через одну модель

Мне интересно, как я могу справиться со следующей ситуацией:

Page имеет_много Assets

Stylesheet имеет_много Assets

Javascript имеет_много Assets

Теперь я хочу иметь возможность выполнять следующие запросы:

Page.first.assets # показывает все активы (таблицы стилей и javascripts) для этой страницы

Page.first.assets.javascripts # показывает все активы javascript для этой страницы (то же самое для таблиц стилей)

Javascript.first.pages # показывает все страницы, которые включают этот javascript (то же самое для таблиц стилей)

В настоящее время у меня есть эта установка:

Assets:
  stylesheet_id
  javascript_id
  page_id

  belongs_to :stylesheet
  belongs_to :javascript
  belongs_to :page

  scope :stylesheets, where{ stylesheet_id != nil } ###
  scope :javascripts, where{ javascript_id != nil } # uses "squeel" gem

Pages:
  has_many :assets
  has_many :stylesheets, through: :assets
  has_many :javascripts, through: :assets

Stylesheets/Javascripts:
  content (text field)

  has_many :assets
  has_many :pages, through: :assets

Проблема не в том, что это не работает

Однако мне кажется, что это неправильный путь, потому что у меня есть три поля *_id в модели Assets. javascript_id, stylesheet_id и page_id. В этой ситуации с каждой строкой либо javascript_id, либо stylesheet_id будет пусто, что мне кажется запахом кода.

Любые предложения, как справиться с этой ситуацией?


person JeanMertz    schedule 25.08.2011    source источник
comment
Полиморфные отношения к спасению.   -  person rubish    schedule 25.08.2011
comment
Хотите уточнить или опубликовать это как ответ вместо комментария? Я пытался искать полиморфные примеры, но почему-то казалось, что то, что я пытался сделать, на самом деле является обратным полиморфным отношением, не так ли? Спасибо за уделенное время.   -  person JeanMertz    schedule 25.08.2011
comment
На самом деле, снова взглянув на свой код и на направляющие рельсы, я начинаю понимать, как это работает. Спасибо! Если вы поместите это как ответ, я могу отметить его или просто опубликую решение, чтобы другие могли его найти.   -  person JeanMertz    schedule 25.08.2011
comment
Лучше поместите свой код в качестве ответа, как только он заработает :)   -  person rubish    schedule 25.08.2011
comment
Попробуйте полиморфную ассоциацию   -  person Rahul    schedule 25.08.2011


Ответы (1)


@rubish Спасибо за помощь, вместе с другими сообщениями stackoverflow у меня теперь есть следующая работа, но я все еще чувствую, что либо слишком усложняю вещи, либо пропускаю некоторую ключевую информацию, но, по крайней мере, это работает (по большей части).

модели/theme.rb

class Theme < ActiveRecord::Base
   attr_accessible #none

   belongs_to :website
   has_many :pages
   has_many :assets, class_name: "ThemeAsset", dependent: :destroy

   has_many :styles, class_name: "AssetStyle", through: :assets, source: :assetable, source_type: "AssetStyle"
   has_many :scripts, class_name: "AssetScript", through: :assets, source: :assetable, source_type: "AssetScript"
 end

модели/theme_asset.rb

class ThemeAsset < ActiveRecord::Base
  attr_accessible :assetable

  belongs_to :assetable, polymorphic: true
  belongs_to :theme
end

модели /asset_style.rb

class AssetStyle < ActiveRecord::Base
  attr_accessible #none

  has_many :assets, class_name: "ThemeAsset",  as: :assetable
end

модели /asset_script.rb

class AssetScript < ActiveRecord::Base
  attr_accessible #none

  has_many :assets, class_name: "ThemeAsset",  as: :assetable
end

Следующее позволяет мне работать с различными активами, но я не знаю, правильно ли это сделать, потому что:

  • theme.assets показывает все theme_asset строки с assetable_id и assetable_type

  • Я не нашел способ по умолчанию отображать только стили или сценарии через theme.assets.scripts, но я думаю, что мог бы использовать для этого scope, как и в моем исходном вопросе.

  • Если я делаю theme.styles.create, стиль сохраняется, но запись не добавляется в таблицу asset, то есть я никогда не смогу найти ее через theme.assets.

  • Единственный способ добавить обе записи — использовать theme.assets.create(assetable: theme.styles.new) (упрощенно).

Правильно ли это, а если нет, может ли кто-нибудь построить поверх моего решения? Заранее спасибо.

person JeanMertz    schedule 28.08.2011