我有一个帖子模型。每个帖子都有标题和许多片段。
class Post < ActiveRecord::Base
has_many :snippets
end
class Snippet < ActiveRecord::Base
belongs_to :post
attr_accessible :position, :post_id
end
我希望有4个不同类型的代码段,例如:
我应该创建四个新模型(称为文本,代码,视频和图像)来扩展代码片段模型吗?:
class Text < Snipppet
attr_accessible :body
end
class Image < Snippet
attr_accessible :image
end
class Video < Snippet
attr_accessible :title
end
class Code < Snippet
attr_accessible code
end
当每个代码段可以是4种不同的内容之一时,如何在视图中引用每个代码段的内容?
在我看来,我想提出这样的事情:
- for snippet in @post.snippets
= place the content of the snippet here
我觉得在片段模型上有一个“类型”字段似乎不是一个好主意,因为这可能会导致数据库和代码的强耦合。在这种情况下,是否有某种铁轨技术可以帮助我?
答案 0 :(得分:5)
实际上,我有点像type
字段。你可以使用single table inheritance的魔力,但众所周知,它是一个脆弱的系统,无论如何,包括一个type
字段。
然后你可以使用polymorphism解决方案,但是有四个不同的表来表示几乎完全相同的东西似乎有点傻。
老实说,使用一个简单的type
字段并根据它改变解释可能会给你最好的结果和最少的麻烦。
就你在模板中所做的事情而言,你可以用耳朵来玩。一个干净的解决方案可能是一个简单的帮助,可以像snippet_content
那样调用,基于type
字段,它会调用助手snippet_content_text
或snippet_content_image
或snippet_content_code
或snippet_content_video
。或者您可以在模板中执行if-then分支,或者引用任意数量的部分模板(但要小心,因为在不必要的情况下使用时会变慢)。
答案 1 :(得分:2)
我喜欢这种方法,但后来我总会遇到一些细微的并发症。
创建适当的视图(texts/_text.html.haml
,images/_image.html.haml
等),以便让Rails为您处理:
= render @post.snippets
喜欢与否:“type”-field是让Rails魔法帮助你创建适当实例的方法。
更新:多态关系也起作用,让每个片段都有自己的表。它是是关系还是表现得像类型的关系?你可以说图像和文本都表现得像代码片段。在这种情况下,请转到名为Snippet
的模块并将其混合。
class Post < ActiveRecord::Base
has_many :snippets, :polymorphic => true
end
class Text < ActiveRecord::Base
include Snippet
belongs_to :post, :as => :snippet
end
module Snippet
# shared behavior here
end
答案 2 :(得分:2)
非常感谢所有回答的人,但我想我已经设法通过使用jystewart的rails 3版acts_as_polymorphs gem
来解决这个问题。以下是我的所作所为:
让我们回忆一下,我们有帖子,我们有四种不同类型的代码。这是6种不同的模型(post.rb,snippet.rb,code.rb.text.rb,image.rb和video.rb)
最大的问题是我们不知道片段是什么类型的对象,因为它可能是4种不同的东西之一。
起初,我尝试使用单表继承执行此操作,但在我看来,对象(代码,文本,视频和图像)彼此之间的差异太大,以至于不能正常工作,我不喜欢事实上它可能会产生大量空的数据库单元,所以我沿着多态路线。
我无法在此处获得标准的多态关联,因为这不是您通常的多态情况。通常,在处理多态时,我们谈论的是像注释模型这样的东西,可以附加到多个其他模型。多态实体总是一样的。但在这种情况下,我们谈论的是片段模型,它可以是4种不同的东西之一。这不是一个简单的belongs_to情况。多态性没有发生。
然后我偶然发现m.onkey.org这篇文章 - 这已经有几年了,但他基本上解释说这种事情需要使用acts_as_polymorphs gem。
所以解决方案是执行以下操作:
has_many_polymorphs
添加到帖子模型这是我的代码:
class Post < ActiveRecord::Base
has_many_polymorphs :snippets, :from => [:codes, :texts, :videos, :images], :through => :snippets
end
class Snippet < ActiveRecord::Base
belongs_to :snippetable, :polymorphic => true
end
class Code < ActiveRecord::Base
# don't have to put anything in here
end
class Text < ActiveRecord::Base
# don't have to put anything in here
end
class Video < ActiveRecord::Base
# don't have to put anything in here
end
class Image < ActiveRecord::Base
# don't have to put anything in here
end
我们唯一需要的是在CreateSnippets迁移中添加一些新字段:
class CreateSnippets < ActiveRecord::Migration
def self.up
create_table :snippets do |t|
t.references :post
t.column :snippetable_id, :integer, :null => false
t.column :snippetable_type, :string, :null => false
t.timestamps
end
end
end
就是这样!令人难以置信的是我现在可以去rails console并执行以下操作:
p = Post.first
p.codes << Code.create(:code=>"This is a code snippet")
p.images << Image.create(:image=>"xyz.png")
p.images << Image.create(:image=>"123.png")
p.codes.count # returns 1
p.images.count # returns 2
p.snippets.count # returns 3 !!!
Yaldi!
无论如何,我花了11天的时间来解决这个问题,它真的让我感到沮丧,我无法做到。我希望这有助于某人。
以下是acts_as_polymorph的一些不错的阅读材料:
进行什么