用Ruby/Rails ORMs建模继承



我正试图为一个简单的博客系统建模这种继承

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

  • 最简单的条目是具有titletextArticle
  • 然而,Quote没有标题,只有简短的text
  • Media具有urlcomment
  • 等等

用RubyonRails对此进行建模的正确方法是什么?那是

  • 我应该为此使用ActiverRecord还是切换到DataMapper
  • 我想避免使用有很多空单元格的"一张大桌子"方法

当我将数据拆分为Entry+PostDataQuoteData等时,在这些数据中是否可以有belongs_to :entry而不在Entry类中有has_one ????这将是在sql中执行此操作的标准方式,并且entry.post_data可以由postdata表中的entry_id解析。

编辑:我不想为博客表建模,我可以这样做,我关心的是条目以及继承如何映射到表。

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

我喜欢这种方法的一点是,您可以在条目模型中保留通用的条目数据。将任何子条目类型的数据抽象到它们自己的数据表中,并与它们有一个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+fields_for来获得正确传递的数据。

这种方法唯一让我头疼的是如何处理控制器和路由助手。由于每个条目都有自己的类型,您必须为每个类型创建自定义控制器/路由(您可能需要…(,或者创建一个通用控制器/路由。如果你采用通用方法,有两件事需要记住。

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

2( 您必须使用becomes()方法(@article.becomes(Entry)(将条目作为entry而非子类进行处理。

希望这能有所帮助。

警告,我过去确实使用过Media作为型号名称。在我的案例中,它在rails 2.3.x中产生了一个名为medias的表,但在rails 3中,它希望我的模型命名为Medium,我的表media。你可能需要在这个命名上添加一个自定义的拐点,尽管我不确定

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

最新更新