2012-04-16 76 views
0

假設我有一個Rails應用程序處理Posts和Comment對象。 A Post has_many評論和每條評論belongs_to a Post。使用rails輔助方法和控制器方法

每個評論有一個word_count財產。帖子對象有一個average_comment_word_count屬性,它是每條評論的word_count的平均值。

第一個問題是如果Post對象異步修改(添加的註釋會影響平均字數),我應該在什麼時候重新計算屬性?當對象返回時?或每次添加新評論?它是否進入評論或發佈幫助器方法?哪個控制器函數應該調用這個方法?

此外,當我包含以下Post助手方法時,我得到一個返回爲JSON的NULL值。

def average_word_count 
    @average_word_count = 0 
    # current_user returns the current user object 
    # user has_many posts and each post belongs_to a user 
    current_user.posts.find(params[:id]).comments.each do |comment| 
     @average_word_count += comment.word_count/current_user.posts.find(params[:id]).comments.count 
    end 

    @average_word_count 
end 

回答

2
class Comment < ActiveRecord::Base 
    belongs_to :post 

    after_save :update_post_word_count 

    def update_post_word_count 
    average_wc = post.comments.average(:word_count) 
    post.update_attributes average_comment_word_count: average_wc 
    end  
end 

或者獲得它,只有當你需要它:

class Post < ActiveRecord::Base 
    has_many :comments 

    def average_comment_word_count 
    comments.average :word_count 
    end 
end 

或者,如果它只是用了一次的地方低流量的,肆無忌憚地蔑視迪米特法則,只是計算它需要從後對象:

Average Comment Word Count: <%= @post.comments.average :word_count %> 

更新:作爲@coreward筆記,這個答案的第一部分是無用的異步我們更新了,但其餘答案可能仍然有幫助。

+0

這做了很多額外的查詢*和*它沒有考慮異步查詢。 – coreyward 2012-04-16 21:15:37

+0

@coreyward,關於異步查詢的好點,但我沒有看到額外的查詢。每個post.comments.average(:foo)都會創建一個單獨的sql語句。 – Mori 2012-04-16 22:38:21

+0

我發現這種方法比客戶計數器緩存更容易實現(也更通用),所以這就是爲什麼我將其標記爲已接受。 – 2012-04-16 22:39:29

1

基於ActiveModel中已有的內容,您可以更好地構建自定義計數器緩存,該緩存可跟蹤總字數,然後只需計算註釋以手動進行數學計算。

# you need a comments_count column and a words_count column in this table 
class Post < ActiveRecord::Base 
    has_many :comments 

    def avg_words_per_comment 
    words_count/comments_count 
    end 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post, :counter_cache => true 
    after_save { update_counters(post.id, :words => word_count } 
    before_destroy { update_counters(post.id, :words => -word_count } 
end 

# And in your view: 

<p> 
    The average comment for this post has <%= @post.avg_words_per_comment %> words. 
</p> 

然後,你不必擔心asynchonicity和視圖的計算是最小的。

https://github.com/rails/rails/blob/master/activerecord/lib/active_record/counter_cache.rb#L65

+0

我沒有使用Rails視圖模板,而是發送了一個JSON響應。除了視圖部分之外,這是否會改變你的答案? – 2012-04-16 22:16:53

+0

另外我想圍繞數值對象屬性進行數學運算。計算單詞是IMO的一個很好的解決方案,但不是一般的案例。感謝您的答案:) – 2012-04-16 22:37:56

+0

@AndrewBarinov我從字面上做了所有的工作,只需輸出參數在您的JSON而不是HTML(JSON是一個視圖,順便說一句)。雖然我不知道你對「關於數值對象屬性的數學運算」有何看法。根據您的帖子,您在Comment中已經有了一個「word_count」方法,而且「post#words_count」和「post#comments_count」都只是數據庫中數字列的訪問者。 – coreyward 2012-04-17 16:31:44