Моделирование наследования с ORM Ruby / Rails

Я пытаюсь смоделировать это наследование для простой системы блога

В блоге много Entries , но они могут быть разными по своей природе. Я не хочу моделировать таблицу в блоге, моя озабоченность связана с записями:

  • Простейшая запись – это Article , имеющая title и text
  • Quote , однако, не имеет названия и имеет короткий text
  • Media есть url и comment
  • и т.д…

Каким образом можно моделировать это с помощью Ruby on Rails? То есть

  • Должен ли я использовать ActiverRecord для этого или переключиться на DataMapper?
  • Я бы хотел избежать подхода «один большой стол» с большим количеством пустых ячеек

Когда я разделяю данные на Entry + PostData , QuoteData т. PostData , QuoteData я иметь belongs_to :entry в этих Datas без has_one ??? в классе Entry ? Это будет стандартный способ сделать это в sql и entry.post_data может быть разрешен entry_id в таблице postdata .

EDIT: я не хочу моделировать таблицу БД, я могу это сделать, моя забота о записях и как наследование будет сопоставлено с таблицей (таблицами).

Я сталкивался с этой проблемой данных несколько раз и пробовал несколько разных стратегий. Я думаю, что я самый большой поклонник, это подход STI, упомянутый циклуном. Убедитесь, что у вас есть столбец type в таблице ввода.

 class Blog < ActiveRecord::Base # this is your generic association that would return all types of entries has_many :entries # you can also add other associations specific to each type. # through STI, rails is aware that a media_entry is in fact an Entry # and will do most of the work for you. These will automatically do what cicloon. # did manually via his methods. has_many :articles has_many :quotes has_many :media end class Entry < ActiveRecord::Base end class Article < Entry has_one :article_data end class Quote < Entry has_one :quote_data end class Media < Entry has_one :media_data end class ArticleData < ActiveRecord::Base belongs_to :article # smart enough to know this is actually an entry end class QuoteData < ActiveRecord::Base belongs_to :quote end class MediaData < ActiveRecord::Base belongs_to :media end 

То, что мне нравится в этом подходе, заключается в том, что вы можете хранить общие данные Entry в модели ввода. Извлеките любой из данных типа подзаголовка в свои собственные таблицы данных и получите для них ассоциацию has_one, в результате чего дополнительные столбцы в таблице записей отсутствуют. Он также отлично работает, когда вы делаете свои взгляды:

 app/views/articles/_article.html.erb app/views/quotes/_quote.html.erb app/views/media/_media.html.erb # may be medium here.... 

и по вашим представлениям вы можете:

 <%= render @blog.entries %> <!-- this will automatically render the appropriate view partial --> 

или иметь больший контроль:

 <%= render @blog.quotes %> <%= render @blog.articles %> 

Вы также можете найти довольно общий способ генерации форм, я обычно делаю общие поля ввода в entries/_form.html.erb . Внутри частичного, у меня также есть

 <%= form_for @entry do |f| %> <%= render :partial => "#{f.object.class.name.tableize}/#{f.object.class.name.underscore}_form", :object => f %> <% end %> 

тип render для данных подформы. accepts_nested_attributes_for в свою очередь, могут использовать accepts_nested_attributes_for + fields_for для правильной передачи данных.

Единственная боль, которую я испытываю при таком подходе, заключается в том, как обращаться с контроллерами и помощниками маршрута. Поскольку каждая запись имеет свой собственный тип, вам придется либо создавать пользовательские контроллеры / маршруты для каждого типа (вам может понадобиться это …), либо создать общий. Если вы возьмете общий подход, нужно запомнить две вещи.

1) Вы не можете установить поле :type через атрибуты обновления, ваш контроллер должен будет создать экземпляр соответствующего Article.new для его сохранения (вы можете использовать завод здесь).

2) Вам нужно будет использовать метод @article.becomes(Entry) becomes() ( @article.becomes(Entry) ) для работы с записью в качестве записи, а не подкласса.

Надеюсь это поможет.

Предупреждение. В прошлом я использовал Media как название модели. В моем случае это привело к таблице, названной medias в rails 2.3.x, однако, в rails 3, она хотела, чтобы моя модель называлась Medium и моими средними таблицами. Возможно, вам придется добавить пользовательский перегиб в этом наименовании, хотя я не уверен.

Вы можете легко справиться с этим с помощью ActiveRecord STI. Это требует, чтобы у вас было поле типа в таблице «Записи». Таким образом вы можете определить свои модели следующим образом:

 def Blog > ActiveRecord::Base has_many :entries def articles entries.where('Type =', 'Article') end def quotes entries.where('Type =', 'Quote') end def medias entries.where('Type =', 'Media') end end def Entry > ActiveRecord::Base belongs_to :blog end def Article > Entry end def Quote > Entry end def Media > Entry end