Rails方式提供修改后的属性

时间:2011-01-26 08:38:05

标签: ruby-on-rails

案例很简单:我的数据库中有markdown,并希望在输出(*)上解析。

@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正确的方法和属性架构。我该怎么做呢?有第五种选择吗?我是否应该了解这些选项中的一个或另一个的陷阱,陷阱或性能问题?

(*)将来可能会更新数据库缓存层,甚至是渲染版本的特殊列。但这仅仅指出了这一点,所以为了避免讨论滤波器输出与滤波器输入之间的关系:)。

4 个答案:

答案 0 :(得分:2)

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

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

就个人而言,我会选择第二或第三种选择。如果你打算从模型中提供它,有一个描述它对身体做了什么的方法将使其他任何人发生的事情变得非常明显。如果html版本的body只会在视图或邮件中使用(这将是合乎逻辑的),我认为将逻辑放在帮助器中会更有意义,因为看起来更合乎逻辑的地方有一个方法输出html。

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

答案 1 :(得分:1)

如果您使用的是HAML,例如app/views/posts/show.html.haml

:markdown
  = @post.body

答案 2 :(得分:1)

另一种方法是使用String方法扩展to_markdown类。这样可以在应用程序的任何位置处理任何字符串

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

@post.body.to_markdown
  

正常粗体 斜体

答案 3 :(得分:0)

body接受parse_with参数的读者?

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)
  

正常粗体 斜体