2011-01-26 86 views
2

这种情况很简单:我在数据库中有markdown,并且希望它在输出(*)上进行解析。Rails提供修改属性的方式

@post.body被映射到数据库中的posts.body列。简单的默认Activerecord ORM。该列存储用户插入的减价文本。

现在,我看到四个方面所提供的降价渲染的版本,我的意见:在app/models/post.rb

首先,:

# ... 
def body 
    markdown = RDiscount.new(body) 
    markdown.to_html 
end 

让我简单地调用@ post.body,并得到一个已经呈现版本。我看到很多潜在的问题,例如在编辑文本字段时预先填充了呈现的HMTL而不是降价代码。

办法是在方法

形式的新属性在app/models/post.rb

# ... 
def body_mardownified 
    markdown = RDiscount.new(body) 
    markdown.to_html 
end 

似乎干净给我。

app/helpers/application_helper.rb

def markdownify(string) 
    markdown = RDiscount.new(string) 
    markdown.to_html 
end 

或者,的帮手第三这是在视图中使用,而不是<%= body %><%= mardownify(body) %>

第四的方式,将解析这个在PostsController

def index 
    @posts = Post.find(:all) 
    @posts.each do |p| 
    p.body = RDiscount.new(string).to_html 
    @rendered_posts << p 
    end 
end 

我不太熟悉Rails 3的正确方法和属性体系结构。我应该怎么去?有第五种选择吗?我应该注意这些选项中的一个或另一个的陷阱,陷阱或性能问题吗?

(*)将来可能会更新数据库缓存层,甚至可能会更新渲染版本的特殊列。但仅此而已,这是不言而喻的,所以要避免讨论过滤输出与过滤输入:)。

回答

1

另一种方式是扩展String类与to_markdown方法。这在你的应用程序

class String 
    def to_markdown 
    RDiscount.new(self) 
    end 
end 

@post.body.to_markdown 

正常上任何地方的任何字符串工作的好处大胆斜体

+0

听起来像一个伟大的,非常Ruby的方式来做到这一点。 – berkes 2011-01-26 20:29:24

2

您描述的第一个选项不会按原样运行。这将导致无限循环,因为当您拨打RDiscount.new(body)时,它将使用您刚定义的body方法传入RDiscount(反过来又会自动再次调用,等等)。如果你想这样做,你需要使用RDiscount.new(read_attribute('body'))

除了这个事实,我认为第一个选项会让有人看到你的应用程序时感到困惑,因为当他们在你的视图@post.body中看到这实际上是身体的修改版本时,它不会立即清楚。

就我个人而言,我会选择第二个或第三个选项。如果你要从模型中提供它,有一个方法来描述它对身体做了什么,这会让其他人知道正在发生的事情。如果html版本的主体只会用在视图或邮件程序中(这将是合乎逻辑的),我认为在帮助程序中使用逻辑更合理,因为它看起来更像一个有逻辑的方法输出html。

不要像第四个想法那样把它放在控制器中,它确实不适合它。

0

怎么样在body读者接受一个parse_with参数使用HAML,例如?

def body(parse_with=nil) 
    b = read_attribute('body') 
    case parse_with 
    when :markdown then RDiscount.new(b) 
    when :escape then CGI.escape(b) 
    else b 
    end 
end 

这种方式,body一个普通的通话将发挥作用,因为它使用的,你可以传递一个参数指定要呈现什么用:

@post.body 

normal **bold** *italic*

@post.body(:markdown) 

normal 大胆斜体