Skip to content

Instantly share code, notes, and snippets.

@Yorgg
Last active November 21, 2023 13:21
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Yorgg/cba16d8cfdc3ffc85ae2 to your computer and use it in GitHub Desktop.
Save Yorgg/cba16d8cfdc3ffc85ae2 to your computer and use it in GitHub Desktop.
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