Rails:当您不知道对象属于哪个类时,尝试输出对象的内容

时间:2010-12-15 23:30:57

标签: ruby-on-rails ruby-on-rails-3 has-many-polymorphs

序言:

不要被My Rails 3应用程序使用has_many_polymorphs gem吓到,因为我不认为您需要熟悉gem以帮助我:)

我的代码:

我有一个Post模型,它有很多Snippets。还有四个其他模型可剪切,即类型 Snippet

class Post < ActiveRecord::Base
  has_many_polymorphs :snippets, 
                      :from => [:texts, :videos, :images, :codes], 
                      :through => :snippets
end

class Snippet < ActiveRecord::Base
  belongs_to :post
  belongs_to :snippetable, :polymorphic => true      
  attr_accessible :post_id, :snippetable_type, :snippetable_id
end

# There following four models are snippetable:

class Code < ActiveRecord::Base
  # note that the attribute name is the same as the Class name
  attr_accessible :code
end

class Text < ActiveRecord::Base
  # note that the attribute name is the same as the Class name
  attr_accessible :text
end

class Image < ActiveRecord::Base
  # note that the attribute name is the same as the Class name
  attr_accessible :image
end

class Video < ActiveRecord::Base
  # note that the attribute name is the same as the Class name
  attr_accessible :video
end

将帖子添加到帖子

现在,如果我想在帖子中添加两个文本片段和两个图片片段,我可以这样做:

# find the first post
p = Post.first

p.texts << Text.create(:text => "This is the first sentence")
p.images << Image.create(:image => "first_image.jpg")
p.texts << Text.create(:text => "This is the second sentence")
p.images << Image.create(:image => "second_image.jpg")

结果是一篇博客文章,如下所示:

  • 文字摘要
  • 图片摘要
  • 文字摘要
  • 图片摘要

我的问题

我在浏览器中显示每个代码段的内容时遇到了一些问题。

可以在我看来执行以下操作:

- for text in @post.texts
  = text.text
- for image in @post.images
  = image.image
- for code in @post.codes
  = code.code
- for video in @post.videos
  = video.video

但是这将导致博客文章如下所示:

  • 文字摘要
  • 文字摘要
  • 图片摘要
  • 图片摘要

我不希望以这种方式按类对片段进行分组。

我该如何解决这个问题?

好吧,我看看这个问题。我知道我 CAN 执行以下操作:

- for snippet in @post.snippets
  = snippet.snippetable_type.downcase

这将输出每个代码段的类名称,如下所示:

  • 文本
  • 图像
  • 文本
  • 图像

但我想要每个片段的内容。

扩展我们上面的内容,因为每种类型的代码段都有一个与Class本身同名的属性,我也可以这样做:

- for snippet in @post.snippets
  = "#{snippet.snippetable_type.downcase}.#{snippet.snippetable_type.downcase}"

这将输出每个代码段的类名和属性名称:

  • text.text
  • image.image
  • text.text
  • image.image

如果我能找到一种获取内容而不是类名的方法,那么我会好的。有人有任何线索吗?

如果有人得到这个,我会非常惊讶。如果你已经读过这篇文章,那就谢谢了。

2 个答案:

答案 0 :(得分:3)

所以你想按for snippet in @post.snippets给你的顺序想要它,但你需要根据snippetable_type发送文字,图片,代码或视频,还是我误读了你?

- for snippet in @post.snippets
  = snippet.snippetable.send(snippet.snippetable_type.downcase)

答案 1 :(得分:1)

我想知道是否(a)这个应用程序和这些片段的复杂程度比你所展示的要多,或者(b)你在不保证开销的情况下使用has_many_polymorphs。

我的意思是:如果这些片段类型除了类名和访问者名称之外确实完全相同,那么根本不需要子类:一个通用的Post类就可以了。

另一方面,如果Post / Snippet类根据类型确实有不同的行为,那么更好的解决方案是使用duck typing来获得所需的输出。 (如果我从你的代码中理解它,这实际上可能是has_many_polymorphs的全部目的。)例如:每个snippetable类型都可以实现一个方法(duck类型).to_html(),其中每个都会创建一个简单的html演示文稿最适合它。然后这个就是你在循环中调用的方法。