我正在尝试为简单的博客系统建模此继承
博客有很多Entries
,但它们的性质可能不同。我不想为Blog表建模,我关心的是条目:
Article
title
和text
Quote
没有标题,并且标题为text
Media
有一个url
和一个comment
... 使用Ruby on Rails对此进行建模的正确方法是什么?那是
当我将数据拆分为Entry
+ PostData
时,QuoteData
等我可以在这些数据中belongs_to :entry
而has_one ???
Entry
类?这是在sql中执行此操作的标准方法,entry.post_data
可以通过entry_id
表中的postdata
解析。{/ p>
编辑:我不想为Blog表建模,我可以这样做,我关心的是条目以及如何将继承映射到表格。
答案 0 :(得分:2)
我多次遇到过这个数据问题,并尝试了一些不同的策略。我认为我最喜欢的那个是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 %> <!-- 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)
)将条目用作条目而不是子类。
希望这有帮助。
警告,我实际上过去曾使用Media作为模型名称。在我的情况下,它导致了一个名为medias in rails 2.3.x的表,但是在rails 3中,它希望我的模型被命名为Medium和我的表媒体。您可能必须在此命名上添加自定义Inflection,但我不确定。
答案 1 :(得分:0)
您可以使用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