Моделирование наследования с помощью Ruby / Rails ORM - PullRequest
0 голосов
/ 27 августа 2011

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

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

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

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

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

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

РЕДАКТИРОВАТЬ: я не хочу моделировать таблицу блога, я могусделайте это, мое беспокойство касается записей и того, как наследование будет сопоставлено с таблицами.

Ответы [ 2 ]

2 голосов
/ 27 августа 2011

Я сталкивался с этой проблемой данных несколько раз и пробовал несколько разных стратегий. Я думаю, что я самый большой поклонник, это подход STI, как упомянуто cicloon. Убедитесь, что в вашей таблице записей есть столбец 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 %> 

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

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

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

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

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

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

0 голосов
/ 27 августа 2011

Вы можете легко справиться с этим, используя 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...