使用Ruby / Rails ORM建模inheritance

我正在尝试为一个简单的博客系统建模这个inheritance

博客有许多Entries ,但它们的性质可能不同。 我不想为Blog表建模,我关心的是条目:

  • 最简单的条目是具有titletext
  • 但是, Quote没有标题并且有短文
  • Mediaurlcomment ……
  • 等等…

使用Ruby on Rails对此进行建模的正确方法是什么? 那是

  • 我应该使用ActiverRecord还是切换到DataMapper?
  • 我想避免使用大量空单元格的“一大表”方法

当我将数据拆分为Entry + PostDataQuoteData等我可以在这些数据中拥有belongs_to :entry而没有has_one ???Entry课程? 这将是在sql和entry.post_data执行此操作的标准方法。可以通过postdata表中的postdata解析postdata

编辑:我不想模拟Blog表,我可以这样做,我关心的是条目以及如何将inheritance映射到表。

我已经多次遇到过这个数据问题,并尝试了一些不同的策略。 我认为我最喜欢的那个是cicloon提到的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 %>  

或者有更多的控制权:

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

您也可以找到生成表单的非常通用的方法,我通常在entries/_form.html.erb partial中呈现通用条目字段。 在那部分里面,我也有一个

 <%= 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 + fields_for来正确传递数据。

我采用这种方法的唯一痛苦是如何处理控制器和路由助手。 由于每个条目都是自己的类型,因此您必须为每种类型创建自定义控制器/路由(您可能需要这样...)或制作通用条目。 如果采用通用方法,需要记住两件事。

1)你不能通过更新属性设置:type字段,你的控制器必须实例化相应的Article.new来保存它(你可以在这里使用工厂)。

2)您必须使用@article.becomes(Entry) becomes()方法( @article.becomes(Entry) )将条目作为Entry而不是子类。

希望这可以帮助。

警告,我实际上过去曾使用Media作为模型名称。 在我的情况下,它导致了一个名为medias in rails 2.3.x的表,但是在rails 3中,它希望我的模型被命名为Medium和我的表媒体。 您可能必须在此命名上添加自定义Inflection,但我不确定。

您可以使用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