2012-04-16 63 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

相关问题