Creating badge and achievements functionality in Ruby on Rails
#Step 1 - Create achievement, badge, and user models | |
#Create an Achivement model | |
#This will contain all of the achievements | |
#model | |
class Achievement < ActiveRecord::Base | |
has_many :badges | |
has_many :users, through: :badges | |
end | |
#table | |
class CreateAchievements < ActiveRecord::Migration | |
def change | |
create_table :achievements do |t| | |
t.text :identity, unique: true, index: true #this is so you dont have to memorize index values | |
t.text :name | |
t.timestamps null: false | |
end | |
end | |
end | |
#Create Badge model | |
#As achievements can belong to many users, and users can have many achievements, | |
#the badge model will serve as the join table | |
#(a user gets a badge when an achievement is met, so I chose the word badge to represent this) | |
class Badge < ActiveRecord::Base | |
belongs_to :user | |
belongs_to :achievement | |
end | |
#table | |
class CreateBadges < ActiveRecord::Migration | |
def change | |
create_table :badges do |t| | |
t.references :user | |
t.references :achievement | |
t.timestamps null: false | |
end | |
end | |
end | |
#Create a User model: | |
class User < ActiveRecord::Base | |
has_many :badges, dependent: :destroy | |
has_many :achievements, through: :badges | |
end | |
#Step 2 - Create a module in Controller concerns directory | |
#Achievements are typically created inside controller actions, | |
#For example, if a user completes x amount of goals, or tasks. | |
#This module checks the conditions needed to create a new badge, if they are met, | |
#the badge is created and a message is added to flash. Include the module in | |
#the controllers and call it with check_achievement(type) - the 'type' argument is the name of the controller. | |
module BadgeCreator | |
def check_achievements(type) | |
send((type + '_achievements').to_sym) | |
end | |
def create_badge(type, name) | |
return if achievement_already_reached?(type) | |
id = Achievement.find_by_identity(type).id | |
current_user.badges.create(achievement_id: id) | |
flash[:achievement] = name | |
end | |
def achievement_already_reached?(type) | |
current_user.achievements.exists?(identity: type) | |
end | |
#This is where you create the custom achievement logic - each method corresponds to a controller | |
#to do: relocate this section - to their own files/module? | |
def task_achievements() | |
#condition(s) | |
task_count = current_user.tasks.count_completed(current_user) | |
#achievements | |
create_badge('10 tasks', 'Complete 10 tasks') if task_count >= 10 | |
create_badge('100 tasks', 'Complete 100 tasks') if task_count >= 100 | |
create_badge('1000 tasks', 'Complete 1000 tasks') if task_count >= 1000 | |
end | |
end | |
class TasksController < ApplicationController | |
include BadgeCreator | |
... | |
def update | |
... | |
if @task.save | |
#Achievement | |
check_achievements("task") #call the method wherever it is needed inside your controller. | |
#the argument is needed to identify the controller. In this example | |
#the #task_achievements() method would be called | |
... | |
end | |
... | |
end | |
... | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment