开发者

Rails: Trying to output the content of an object when you don't know what class the object belongs to

开发者 https://www.devze.com 2023-01-30 15:09 出处:网络
Preamble: Don\'t be scared off by the fact My Rails 3 app uses the has_many_polymorphs gem as I don\'t think you need to be familiar with the gem in order to help me here :)

Preamble:

Don't be scared off by the fact My Rails 3 app uses the has_many_polymorphs gem as I don't think you need to be familiar with the gem in order to help me here :)

My code:

I have a Post model which has many Snippets. There are four additional models which are snippetable i.e. of type 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 < A开发者_如何学PythonctiveRecord::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

Adding snippets to a Post

Now if I want to add two text snippets and two image snippets to a post I can do this:

# 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")

The result is a blog post that looks like this:

  • text snippet
  • image snippet
  • text snippet
  • image snippet

My Problem

I'm having some trouble displaying the content of each snippet in my view.

I could do the following in my view:

- 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

BUT this will result in a blog post that looks like this:

  • text snippet
  • text snippet
  • image snippet
  • image snippet

I don't want snippets to be grouped by Class in this way.

How can I solve this?

Well I've a look at the problem. I know that I CAN do the following:

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

and this will output the Class name of each snippet as shown:

  • text
  • image
  • text
  • image

BUT I want the content of each snippet.

Expanding on what we have above, since each type of snippet has one attribute with the same name as the Class itself, I can also do this:

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

And this will output the classname AND the attribute name of each snippet:

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

If I could just find a way of getting to the content and not the Classnames then I'd be ok. Anyone got any clue?

I will be absolutely amazed if anyone gets this one. Thanks if you have read this far.


So you want it in the order that for snippet in @post.snippets gives you, but you need it to send text, image, code or video depending on the snippetable_type, or am I misreading you?

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


I'm wondering if either (a) there's more complexity to this app and these snippets than you're showing, or (b) you're using has_many_polymorphs in a situation that doesn't warrant the overhead.

What I mean is: if these snippet types are really all identical except for the class name and accessor name, then you don't need the subclasses at all: one generic Post class will do.

On the other hand, if the Post/Snippet classes do have different behavior depending on type, then a better solution would be to use duck typing to get the output you want. (And this may actually be the entire purpose of has_many_polymorphs if I understand it from your code.) For example: Each snippetable type could implement a method (the duck type) .to_html() in which each one would create a bare-bones html presentation most appropriate to it. And then this is the method you'd call inside your loop.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号