Increase Engagement with Merit and Gamification
Gamification or reputation systems have become quite popular with web and mobile apps. Keeping score of users’ activity helps websites find out who should be rewarded and encourages users to contribute. Websites like StackOverflow and Foursquare are two of the common applications that owe much of their success to gamification. These reputation systems have been in use on forums and communities for a long time and work well in building a quality user engagements.
There are a couple of gems that can help seamlessly build a gamified experience for users. One of the gems that I feel is quite useful, customizable, and well maintained is merit.
The simple rule behind gamification is that when a user performs an action or achieves a quantifiable goal, there is a reward. For example:
* When a user comments 10 they are given a Junior Critic Badge
* When the user posts 5 articles they are given the Junior Contributor Badge
Setup Merit
To get started with Merit, add the following code to your gem file.
gem 'merit'
run
bundle install
Once the bundle is complete, add the initializer and migration. The initializer mentions the name of the badges we want use. We can also define which datastore we plan to use (PostgreSQL or mongoDB). In the migration, the model to be “gamified” is specified. For example, we are going to track user activity, so we need to add the migration to the User model:
bundle exec rails g merit:install
=> Creates the initializer in /config/initializer/merit.rb
bundle exec rails g merit model_name (eg: user)
=> would add has_merit to the user model
Now migrate the database:
bundle exec rake db:migrate
Another folder to be aware of is the app/models/merit/*. This directory holds the definitions of the rules for the badges given to users. The ability to write the rules in a plain Ruby file is one the major advantages of using Merit. Using a file based approach makes it highly customizable.
Let’s create our first badge.
The badges we plan to use need to be written in the initializer file config/initializers/merit.rb. The method to create a badge is Merit::Badge.create!
. It accepts the following parameters:
:id
integer (required):name
this is how you reference the badge (required):level
(optional):description
(optional):custom_fields
hash of anything else you want associated with the badge (optional)
Example:
Merit::Badge.create!(
id: 1,
name: "Jr.Critic",
description: "Over 10 comments"
)
Merit::Badge.create!(
id: 2,
name: "Sr.Critic",
description: "Over 50 comments"
)
Once the badge is created, it’s time to define the rules to award this badge to the user. As mentioned before, the rules to award the badge are defined in the app/models/merit/* folder. We need to create a file callled badge_rules.rb. Note that we can provide a temporary or permanent badge. A temporary badge is revoked when its rules are no longer met.
The rules are defined by calling the grant_on
method and providing a block. The parameters that for this method are:
'controller#action'
– The name of the controller and action that triggers the block:badge
– The:name
of the badge:level
– The:level
of the badge:to
– The name of object that holds the badge receiver. It needs a variable named@model
in the associated controller action, like@post
forposts_controller.rb
or@comment
forcomments_controller.rb
- Can be a method name, which called over the target object should retrieve the object to badge. If it’s
:user
for example, merit will internally call@model.user
to find who to badge - Can be
:itself
, in which case it badges the target object itself (@model
) - Is
:action_user
by default, which meanscurrent_user
- Can be a method name, which called over the target object should retrieve the object to badge. If it’s
:model_name
– Defines the controller’s name if it’s different from the model’s (e.g.RegistrationsController
for theUser
model).:multiple
– Whether or not the badge may be granted multiple times.false
by default.:temporary
– Whether or not the badge should be revoked if the condition no longer holds.false
-badges are kept for ever- by default.&block
– Can be one of the following:- Empty / not included: always grant the badge
- A block which evaluates to boolean. It receives the target object as a parameter (e.g.
@post
if you’re working with aPostsController
action). - A block with a hash composed of methods to run on the target object and expected method return values
Example:
# app/models/merit/badge_rules.rb
grant_on 'comments#create', badge: 'Jr.Critic', to: :user do |comment|
comment.user.comments.count >= 10 && comment.user.comments.count < 50
end
grant_on 'comments#create', badge: 'Sr.Critic', to: :user do |comment|
comment.user.comments.count >= 50
end
It’s clear from the above code that the Junior Critic badge will last only as long as the user’s comments count is greater than 10 and less than 50. When his comment count goes to more than 50, a new badge will be issued and The Junior Badge will be removed.
To access the badges of the current user (assuming that your logged in user is known as current_user
):
current_user.badges
If you want add/remove badges manually, use:
current_user.add_badge(badge.id)
current_user.rm_badge(badge.id)
An example use case for the above situation is when you want to give a ‘premium user’ badge for paying customers. Instead of writing a rule and have it checked many times, just add it from the payment controller and action.
Point System
From here, we can build a cool reputation system, but t won’t be complete without displaying points. The calculation of points is similar to the badge system. Define the point rules in a file called (you guessed it) app/models/merit/point_rules.rb.
Points are configured using a method called score
that accepts the same parameters as the badge system.
For example, if you require the user’s points to increase by one when he comments on an article:
score 1, on: 'comments#create', to: [:user]
score 5, on: 'comments#vote_up', to: [:comment_owner]
:user
is the the attribute of the model (comment) that points to the user. In the case of vote_up
, the owner of the comment was referenced by an attribute in the Vote
model as comment_owner
.
You can manually add points, just like badges:
current_user.add_points(20, category: 'Optional category')
current_user.subtract_points(10, category: 'Optional category')
To find the points awarded since a given date say, for a leaderboard, use:
score_points = current_user.score_points(category: 'Optional category')
score_points.where("created_at > '#{1.month.ago}'").sum(:num_points)
Ranking system
Similar to both points and badges, ranking is defined in app/models/merit/rank_rules.rb.
Ranking rules are created with the set_rank
method. The parameters are as follows:
:level
– Ranking level (greater is better, Lexicographical order):to
– Model or scope to check if new rankings apply:level_name
– Attribute name (default is empty and results in ‘level’ attribute, if set it’s appended like ‘level_#{level_name}’)
Example:
set_rank level: 2, to: User.active do |user|
user.comments > 10 && user.followers >= 10
end
This is more functionality available with Merit. Using something like ActiveRecord Observer, it is simple to track the badges/points being awarded and create the required notification for users. Try out the gem and bring gamification and, thus, more engagement to your web application.