我正试图为一个简单的博客系统建模这种继承
博客有许多Entries
,但它们的性质可能不同。我不想为博客表建模,我关心的是条目:
- 最简单的条目是具有
title
和text
的Article
- 然而,
Quote
没有标题,只有简短的text
Media
具有url
和comment
- 等等
用RubyonRails对此进行建模的正确方法是什么?那是
- 我应该为此使用ActiverRecord还是切换到DataMapper
- 我想避免使用有很多空单元格的"一张大桌子"方法
当我将数据拆分为Entry
+PostData
、QuoteData
等时,在这些数据中是否可以有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