-
Notifications
You must be signed in to change notification settings - Fork 0
Home
π referral_box is a flexible Ruby gem for integrating referral and loyalty systems into your Rails applications with ease.
- Points system (e.g., earn 10 points per βΉ100 spent)
- Tiered rewards (e.g., Silver, Gold, Platinum)
- Points expiration support
- Redeem points with custom logic
- Track user point history
- Unique referral codes per user
- Track signups via referral
- Reward both referrer and referee
- Custom reward logic for referrals
- Getting Started
- Configuration
- Loyalty System
- Referral System
- Callbacks & Events
- Advanced Usage
- Troubleshooting
- Quick Start
- Installation
- Configuration
- Flexible Model Support
- Core Features
- API Reference
- Admin Dashboard
- Advanced Usage
- Troubleshooting
- Examples
Add to your Gemfile and get started in minutes:
# Gemfile
gem 'referral_box'
bundle install
rails generate referral_box:install
rails db:migrate
Visit /referral_box
to see your admin dashboard!
# Gemfile
gem 'referral_box'
bundle install
rails generate referral_box:install
This will:
- Create
config/initializers/referral_box.rb
- Ask if you want to add columns to your model
- Set up basic configuration
rails db:migrate
This creates:
-
referral_box_transactions
table -
referral_box_referral_logs
table - Adds
referral_code
andtier
columns to your model table
Add to your model file (e.g., app/models/user.rb
, app/models/customer.rb
, etc.):
class User < ApplicationRecord # or Customer, Account, etc.
has_many :referral_box_transactions, class_name: 'ReferralBox::Transaction', as: :user
has_many :referrals, class_name: 'User', foreign_key: 'referrer_id'
belongs_to :referrer, class_name: 'User', optional: true
before_create :generate_referral_code
def points_balance
ReferralBox.balance(self)
end
def current_tier
ReferralBox.tier(self)
end
def referral_link
"#{Rails.application.routes.url_helpers.root_url}?ref=#{referral_code}"
end
private
def generate_referral_code
return if referral_code.present?
loop do
self.referral_code = SecureRandom.alphanumeric(ReferralBox.configuration.referral_code_length).upcase
break unless User.exists?(referral_code: referral_code)
end
end
end
ReferralBox works with ANY model! You're not limited to just User
. Here are examples:
# config/initializers/referral_box.rb
ReferralBox.configure do |config|
config.reference_class_name = 'Customer'
# ... other config
end
# app/models/customer.rb
class Customer < ApplicationRecord
has_many :referral_box_transactions, class_name: 'ReferralBox::Transaction', as: :user
has_many :referrals, class_name: 'Customer', foreign_key: 'referrer_id'
belongs_to :referrer, class_name: 'Customer', optional: true
before_create :generate_referral_code
def points_balance
ReferralBox.balance(self)
end
def current_tier
ReferralBox.tier(self)
end
def referral_link
"#{Rails.application.routes.url_helpers.root_url}?ref=#{referral_code}"
end
private
def generate_referral_code
return if referral_code.present?
loop do
self.referral_code = SecureRandom.alphanumeric(ReferralBox.configuration.referral_code_length).upcase
break unless Customer.exists?(referral_code: referral_code)
end
end
end
# config/initializers/referral_box.rb
ReferralBox.configure do |config|
config.reference_class_name = 'Account'
# ... other config
end
# app/models/account.rb
class Account < ApplicationRecord
has_many :referral_box_transactions, class_name: 'ReferralBox::Transaction', as: :user
has_many :referrals, class_name: 'Account', foreign_key: 'referrer_id'
belongs_to :referrer, class_name: 'Account', optional: true
before_create :generate_referral_code
def points_balance
ReferralBox.balance(self)
end
def current_tier
ReferralBox.tier(self)
end
def referral_link
"#{Rails.application.routes.url_helpers.root_url}?ref=#{referral_code}"
end
private
def generate_referral_code
return if referral_code.present?
loop do
self.referral_code = SecureRandom.alphanumeric(ReferralBox.configuration.referral_code_length).upcase
break unless Account.exists?(referral_code: referral_code)
end
end
end
# config/initializers/referral_box.rb
ReferralBox.configure do |config|
config.reference_class_name = 'Member'
# ... other config
end
# app/models/member.rb
class Member < ApplicationRecord
has_many :referral_box_transactions, class_name: 'ReferralBox::Transaction', as: :user
has_many :referrals, class_name: 'Member', foreign_key: 'referrer_id'
belongs_to :referrer, class_name: 'Member', optional: true
before_create :generate_referral_code
def points_balance
ReferralBox.balance(self)
end
def current_tier
ReferralBox.tier(self)
end
def referral_link
"#{Rails.application.routes.url_helpers.root_url}?ref=#{referral_code}"
end
private
def generate_referral_code
return if referral_code.present?
loop do
self.referral_code = SecureRandom.alphanumeric(ReferralBox.configuration.referral_code_length).upcase
break unless Member.exists?(referral_code: referral_code)
end
end
end
rails generate migration AddReferralBoxToCustomers referral_code:string tier:string referrer:references
rails generate migration AddReferralBoxToAccounts referral_code:string tier:string referrer:references
rails generate migration AddReferralBoxToMembers referral_code:string tier:string referrer:references
-
Change
reference_class_name
in your initializer - Update model associations to use your model name
-
Update
generate_referral_code
method to use your model - Run appropriate migrations for your model table
# With Customer model
customer = Customer.create!(email: "john@example.com")
ReferralBox.earn_points(customer, 100)
balance = ReferralBox.balance(customer)
# With Account model
account = Account.create!(name: "Business Account")
ReferralBox.earn_points(account, 100)
tier = ReferralBox.tier(account)
# With Member model
member = Member.create!(username: "john_doe")
ReferralBox.earn_points(member, 100)
referral_link = member.referral_link
# config/initializers/referral_box.rb
ReferralBox.configure do |config|
# Define your model (User, Customer, Account, Member, etc.)
config.reference_class_name = 'User' # or 'Customer', 'Account', etc.
# Points earning rule
config.earning_rule = ->(user, event) do
# Example: earn 10 points per βΉ100 spent
event.amount / 10
end
# Tier thresholds
config.tier_thresholds = {
"Silver" => 500,
"Gold" => 1000,
"Platinum" => 2500
}
# Reward multiplier by tier
config.reward_modifier = ->(user) do
case user.tier
when "Silver" then 1.0
when "Gold" then 1.2
when "Platinum" then 1.5
else 1.0
end
end
# Referral rewards
config.referral_reward = ->(referrer, referee) do
ReferralBox.earn_points(referrer, 100)
ReferralBox.earn_points(referee, 50)
end
# Points expiration (days)
config.points_expiry_days = 90
# Referral code length
config.referral_code_length = 8
# Admin dashboard path
config.admin_route_path = "/referral_box"
end
Option | Type | Default | Description |
---|---|---|---|
reference_class_name |
String | 'User' | Your model class name (User, Customer, Account, etc.) |
earning_rule |
Lambda | ->(user, event) { 1 } |
Custom points earning logic |
redeem_rule |
Lambda | ->(user, offer) { 100 } |
Custom points redemption logic |
tier_thresholds |
Hash | {"Silver"=>500, "Gold"=>1000, "Platinum"=>2500} |
Points needed for each tier |
reward_modifier |
Lambda | ->(user) { 1.0 } |
Points multiplier by tier |
referral_reward |
Lambda | nil |
Logic for referral rewards |
points_expiry_days |
Integer | 90 | Days until points expire |
referral_code_length |
Integer | 8 | Length of referral codes |
admin_route_path |
String | '/referral_box' | Admin dashboard URL path |
on_tier_changed |
Lambda | nil |
Callback when user tier changes |
# Basic earning
ReferralBox.earn_points(user, 100)
# With event data
ReferralBox.earn_points(user, 100, event: order)
# Custom earning rule (defined in config)
ReferralBox.earn_points(user, order.amount, event: order)
# Redeem points
ReferralBox.redeem_points(user, 50)
# With offer data
ReferralBox.redeem_points(user, 50, offer: coupon)
# Get current balance
balance = ReferralBox.balance(user)
# Check if user has enough points
if ReferralBox.balance(user) >= 100
# Process redemption
end
# Get current tier
tier = ReferralBox.tier(user)
# Returns: "Silver", "Gold", "Platinum", or nil
# Check if user is in specific tier
if ReferralBox.tier(user) == "Gold"
# Apply Gold tier benefits
end
# In your initializer
config.on_tier_changed = ->(user, old_tier, new_tier) do
UserMailer.tier_changed(user, old_tier, new_tier).deliver_later
end
# Track when someone clicks a referral link
ReferralBox.track_referral(
ref_code: params[:ref],
user_agent: request.user_agent,
ip_address: request.remote_ip
)
# When new user signs up with referral code
ReferralBox.process_referral_signup(new_user, ref_code)
# Get referral statistics
total_clicks = ReferralBox::ReferralLog.clicked_count
total_conversions = ReferralBox::ReferralLog.converted_count
conversion_rate = ReferralBox::ReferralLog.conversion_rate
Earns points for a user.
Parameters:
-
user
- User object (or Customer, Account, etc.) -
amount
- Points to earn (integer) -
event
- Optional event object for custom earning rules
Returns: Transaction object or false
Example:
transaction = ReferralBox.earn_points(user, 100, event: order)
Redeems points from a user's balance.
Parameters:
-
user
- User object (or Customer, Account, etc.) -
points
- Points to redeem (integer) -
offer
- Optional offer object
Returns: Transaction object or false
Example:
transaction = ReferralBox.redeem_points(user, 50, offer: coupon)
Gets the current points balance for a user.
Parameters:
-
user
- User object (or Customer, Account, etc.)
Returns: Integer (points balance)
Example:
balance = ReferralBox.balance(user)
Gets the current tier for a user.
Parameters:
-
user
- User object (or Customer, Account, etc.)
Returns: String (tier name) or nil
Example:
tier = ReferralBox.tier(user)
Tracks a referral link click.
Parameters:
-
ref_code
- Referral code (required) -
user_agent
- Browser user agent -
ip_address
- IP address -
referrer
- Referrer URL
Returns: ReferralLog object or false
Example:
log = ReferralBox.track_referral(
ref_code: params[:ref],
user_agent: request.user_agent,
ip_address: request.remote_ip
)
Processes a referral signup.
Parameters:
-
referee
- New user who signed up (or Customer, Account, etc.) -
ref_code
- Referral code used
Returns: Boolean (success/failure)
Example:
success = ReferralBox.process_referral_signup(new_user, ref_code)
user.points_balance # Get points balance
user.current_tier # Get current tier
user.referral_link # Get referral link URL
user.total_referrals # Count total referrals
user.successful_referrals # Count successful referrals
Visit: http://your-app.com/referral_box
-
Overview Dashboard
- Total users, transactions, referrals
- Conversion rate
- Recent transactions
- Top users by points
-
Users Management
- List all users with points and tiers
- View user details
- See referral codes
-
Transactions
- Complete transaction history
- Filter by type (earn/redeem)
- Search and pagination
-
Referrals
- Referral click tracking
- Conversion analytics
- Device and browser stats
-
Analytics
- Referral performance
- Device breakdown
- Daily click trends
# In your initializer
config.admin_route_path = "/admin/referral_box"
# Points based on order amount
config.earning_rule = ->(user, event) do
case event.class.name
when 'Order'
event.amount / 10 # 10 points per $1
when 'Review'
50 # 50 points for reviews
else
1 # Default 1 point
end
end
# Dynamic tier calculation
config.tier_thresholds = ->(user) do
if user.vip?
{ "VIP" => 100, "VIP Gold" => 500, "VIP Platinum" => 1000 }
else
{ "Bronze" => 100, "Silver" => 500, "Gold" => 1000 }
end
end
# Complex referral rewards
config.referral_reward = ->(referrer, referee) do
# Give referrer points
ReferralBox.earn_points(referrer, 100)
# Give referee welcome bonus
ReferralBox.earn_points(referee, 50)
# Send notifications
ReferralMailer.welcome_bonus(referee).deliver_later
ReferralMailer.referral_bonus(referrer).deliver_later
end
# Custom expiration logic
config.points_expiry_days = ->(user, points) do
if user.vip?
365 # VIP users get 1 year
else
90 # Regular users get 90 days
end
end
# In your Order model
class Order < ApplicationRecord
belongs_to :user # or customer, account, etc.
after_create :award_points
private
def award_points
ReferralBox.earn_points(user, order_total, event: self)
end
end
# In your Coupon model
class Coupon < ApplicationRecord
def apply_to_order(order)
points_cost = cost_in_points
if ReferralBox.balance(order.user) >= points_cost
ReferralBox.redeem_points(order.user, points_cost, offer: self)
order.apply_discount(discount_amount)
end
end
end
# In your ApplicationController
class ApplicationController < ActionController::Base
before_action :track_referral
private
def track_referral
if params[:ref].present?
ReferralBox.track_referral(
ref_code: params[:ref],
user_agent: request.user_agent,
ip_address: request.remote_ip
)
end
end
end
# In your UsersController (or CustomersController, etc.)
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
# Process referral if present
if session[:referral_code].present?
ReferralBox.process_referral_signup(@user, session[:referral_code])
end
redirect_to @user
else
render :new
end
end
end
# API endpoint for points balance
class Api::ReferralBoxController < ApplicationController
def balance
render json: {
balance: ReferralBox.balance(current_user),
tier: ReferralBox.tier(current_user),
referral_code: current_user.referral_code
}
end
def earn_points
amount = params[:amount].to_i
transaction = ReferralBox.earn_points(current_user, amount)
if transaction
render json: { success: true, new_balance: ReferralBox.balance(current_user) }
else
render json: { success: false, error: "Failed to earn points" }
end
end
end
Problem: Kaminari pagination not working
Solution: The gem includes Kaminari automatically. If you still get errors, restart your Rails server:
rails server
Problem: Gem not loaded properly
Solution:
bundle install
rails server
Problem: Database migration fails
Solution:
rails db:rollback
rails db:migrate
Problem: Dashboard routes not working
Solution: Check your routes.rb file. The gem should auto-mount at /referral_box
.
Problem: Referral codes not created automatically
Solution: Make sure your model has the before_create :generate_referral_code
callback.
Enable debug logging:
# In your initializer
ReferralBox.configure do |config|
config.debug = true
end
# In Rails console
puts ReferralBox.configuration.reference_class_name
puts ReferralBox.configuration.tier_thresholds
# config/initializers/referral_box.rb
ReferralBox.configure do |config|
config.reference_class_name = 'Customer' # Using Customer model
config.earning_rule = ->(customer, event) do
case event.class.name
when 'Order'
event.amount / 10 # 10 points per $1
when 'Review'
50 # 50 points for reviews
when 'Referral'
100 # 100 points for referrals
else
1
end
end
config.tier_thresholds = {
"Bronze" => 100,
"Silver" => 500,
"Gold" => 1000,
"Platinum" => 2500
}
config.reward_modifier = ->(customer) do
case customer.tier
when "Bronze" then 1.0
when "Silver" then 1.1
when "Gold" then 1.2
when "Platinum" then 1.5
else 1.0
end
end
config.referral_reward = ->(referrer, referee) do
ReferralBox.earn_points(referrer, 100, event: OpenStruct.new(class: { name: 'Referral' }))
ReferralBox.earn_points(referee, 50, event: OpenStruct.new(class: { name: 'Referral' }))
end
config.points_expiry_days = 90
config.referral_code_length = 8
end
class Customer < ApplicationRecord
has_many :referral_box_transactions, class_name: 'ReferralBox::Transaction', as: :user
has_many :referrals, class_name: 'Customer', foreign_key: 'referrer_id'
belongs_to :referrer, class_name: 'Customer', optional: true
before_create :generate_referral_code
def points_balance
ReferralBox.balance(self)
end
def current_tier
ReferralBox.tier(self)
end
def referral_link
"#{Rails.application.routes.url_helpers.root_url}?ref=#{referral_code}"
end
def can_redeem?(points)
ReferralBox.balance(self) >= points
end
def tier_benefits
case current_tier
when "Gold"
{ discount: 0.1, free_shipping: true }
when "Platinum"
{ discount: 0.15, free_shipping: true, priority_support: true }
else
{ discount: 0.05, free_shipping: false }
end
end
private
def generate_referral_code
return if referral_code.present?
loop do
self.referral_code = SecureRandom.alphanumeric(ReferralBox.configuration.referral_code_length).upcase
break unless Customer.exists?(referral_code: referral_code)
end
end
end
- Check the documentation - This guide covers most use cases
- Review the examples - See working implementations
-
Check the admin dashboard -
/referral_box
for debugging - Use Rails console - Test methods directly
# Test basic functionality
customer = Customer.first # or User.first, Account.first, etc.
ReferralBox.earn_points(customer, 100)
puts ReferralBox.balance(customer)
puts ReferralBox.tier(customer)
# Check configuration
puts ReferralBox.configuration.reference_class_name
puts ReferralBox.configuration.tier_thresholds
# Test referral tracking
ReferralBox.track_referral(ref_code: customer.referral_code)
# Check transaction history
ReferralBox::Transaction.where(user: customer).count
puts ReferralBox::VERSION
MIT License - See LICENSE.txt for details.
Happy coding with ReferralBox! π