【问题标题】:Utilizing rails helper and controller methods使用 rails helper 和 controller 方法
【发布时间】:2012-04-16 20:15:07
【问题描述】:

假设我有一个处理 Posts 和 Comment 对象的 Rails 应用程序。一个帖子has_many 评论和每个评论belongs_to 一个帖子。

每个评论都有一个word_count 属性。 Post 对象有一个average_comment_word_count 属性,它是每个评论的word_count 的平均值。

第一个问题是如果 Post 对象被异步修改(添加 cmets 会影响平均字数),我应该在什么时候重新计算属性?什么时候返回对象?或者每次添加新评论时?它是否进入评论或发布帮助方法?哪个控制器函数应该调用这个方法?

此外,当我包含以下 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

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3.2


    【解决方案1】:
    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 所说,此答案的第一部分对异步更新没有用,但答案的其余部分可能仍然有用。

    【讨论】:

    • 这会进行很多额外的查询并且它无法考虑异步查询。
    • @coreyward,关于异步查询的好点,但我没有看到额外的查询。每个 post.cmets.average(:foo) 创建一个 sql 语句。
    • 我发现这种方法比客户计数器缓存更容易实现(也更通用),因此我将其标记为已接受。
    • @mori 对于您触发附加查询的每个帖子。如果返回帖子列表,则表示您正在执行一连串查询以重新计算数据。
    【解决方案2】:

    您最好根据 ActiveModel 中已有的内容构建一个自定义计数器缓存来跟踪总字数,然后只计算 cmets 以手动进行数学运算。

    # 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>
    

    那么您无需担心异步性,并且视图上的计算量很小。

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

    【讨论】:

    • 我没有使用 Rails 视图模板,而是发送 JSON 响应。除了视图部分之外,这是否会改变您的答案?
    • 另外,我正试图集中精力对数值对象属性执行数学运算。数词是 IMO 的一个很好的解决方案,但不是一般情况下的解决方案。不过感谢您的回答:)
    • @AndrewBarinov 我确实完成了所有工作,只需在 JSON 中输出参数而不是 HTML(JSON 是一个视图,顺便说一句)。我不知道你在做什么关于“数字对象属性的数学运算”。根据您的帖子,您在 Comment 上已经有一个 word_count 方法,并且 post#words_countpost#comments_count 都只是数据库中数字列的访问器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-19
    • 2012-01-26
    • 1970-01-01
    相关资源
    最近更新 更多