2011-01-26 88 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 大膽斜體