2

我有一个用户和帖子模型,并且正在使用acts_as_votable gem(它给我一个“投票”表)来支持/反对一个帖子。我想为每个用户分配业力,其中业力是用户从他/她的所有帖子中获得的赞成票数减去反对票总数。

目前我在用户模型上有这个实例方法来计算业力:

  def karma
    count = 0
    self.posts.each do |post|
      count += post.upvotes.size - post.downvotes.size
    end
    return count
  end

我不认为上面的运行时间为 O(2n) 时效率很高,因为对于每个帖子都需要两个额外的数据库查询,一个用于赞成票,一个用于反对票。

关于如何将上述内容组合成一个查询或以其他方式使其更有效的任何想法?

4

1 回答 1

1

不仅效率方面,这样的设计在 OOP 方面也不好。User 模型考虑的太多超出了它的范围。业力是属于用户的东西,不应与其他任何东西捆绑在一起。

更好的方法是将“Karma”与 Post 分开。

# Add a "karma" column
$ rails g migration AddKarmaToUser

# Or use a dedicated table
class User < ActiveRecord::Base
  has_one :karma

然后,使用控制器或服务对象来改变业力。为简单起见,我将在这里介绍 Controller。不要使用模型回调,因为那是跨模型。

class PostsController < ApplicationController
  def upvote
    post = Post.find(params[:id])
    post.upvote # pseudo API of acts_as_votable
    current_user.increase_karma
  end

  def downvote
    # ...
    current_user.decrease_karma
  end
end

# Model
class User < ActiveRecord::Base
  attr_accessible :karma

  def increase_karma(count=1)
    update_attribute(:karma, karma + count)
  end

  def descrease_karma(count=1)
    # ...
  end
end

# View
user.karma
于 2013-10-07T05:41:24.960 回答