-
Notifications
You must be signed in to change notification settings - Fork 123
Build Hacker News Like Reputation System
Let's define Hacker News like Reputation System using ActiveRecord Reputation System gem.
At Hacker News, user can post news and make comments about them. Let's define user, post and comment classes:
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
class Post < ActiveRecord::Base
belong_to :user
end
class Comment < ActiveRecord::Base
belong_to :user
end
Users can give points to comments and points. Let's define a reputation for posts and comments:
class Post < ActiveRecord::Base
belong_to :user
has_reputation :post_points,
:source => :user
end
class Comment < ActiveRecord::Base
belong_to :user
has_reputation :comment_points,
:source => :user
end
Here I ommitted :aggregated_by
option because it's :sum
by default and that's what we want here.
Now you can give points to posts and comments as follow:
@post.add_evaluation(:post_points, 1, @user)
@comment.add_evaluation(:comment_points, 1, @user)
For the top news page, you can order posts by points:
@posts = Post.find_with_reputation(:post_points, :all, { :order => 'post_points DESC' })
In a view, you can do something like:
<% @posts.each do |post| %>
<%= post.title %> has <%= post.post_points %> points.
<% end %>
Hacker News also keep track of user karma. Let's define user karma as a sum of the user's post points and comment points.
class User < ActiveRecord::Base
has_many :posts
has_many :comments
has_reputation :karma
:source => [
{ :reputation => :total_post_points },
{ :reputation => :total_comment_points }
]
has_reputation :total_post_points,
:source => { :reputation => :post_points, :of => :posts }
has_reputation :total_comment_points
:source => { :reputation => :comment_points, :of => :comments }
end
Here I omitted :source_of
for :total_post_point
and :total_comment_points
because the gem can detect it if it's within the same class. But you need to define it for :post_points
and :comment_points
like below because they are now source of :total_post_points
and :total_comment_points
.
class Post < ActiveRecord::Base
belong_to :user
has_reputation :post_points,
:source => :user,
:source_of => { :reputation => :total_post_points, :of => :user }
end
class Comment < ActiveRecord::Base
belong_to :user
has_reputation :comment_points,
:source => :user,
:source_of => { :reputation => :total_comment_points, :of => :user }
end
Now you can access user karma as follow:
@user.reputation_for(:karma)
You might want to get all posts for which the user gave a point. You can do this by:
@evaluated_posts = Post.evaluated_by(:post_points, @user)
Also, you can get all users who gave a point for a given post:
@post.evaluators_for(:post_points)
Now we have Hacker News like a Reputation System!
As you can see, the relationship among reputations is defined in very readable way. You can easily understand how each reputations related to each other by just looking at the has_reputation
definition in models. Also all reputation value propagations are handled by gem which prevents you from writing a code related to the reputation system in various places.
Ready to build your own reputation system? For more infomation, please explore the ActiveRecord Reputation System Wiki.