Adding referrals to a Rails app using Stripe

Hi.

It’s been a while.

I want to talk about adding a referral program to a Rails app when using Stripe. One of the ways to grow your online business is to reward existing customers for referring new customers. People buy from other people. Right?

Leavetrack uses Stripe to handle subscriptions and I wanted to implement a scheme where existing customers could, when they added their card details, enter a referral code so the referring account would receive a credit. Pretty straightforward, one referral gets 10% off, two referrals gets 20% off, to a maximum of 50% off the monthly subscription.

There are some commercial solutions out there but I think this is fairly trivial to implement for the scope I have.

The first step is to create a migration to add a referral code to each account.

class AddReferralCodeToAccount < ActiveRecord::Migration
   def change
     add_column :accounts, :referral_code, :string, null: false, unique: true
     Account.all.each do |account|
       account.update_attribute(:referral_code, SecureRandom.hex(3))
     end
  end
end

Follow this by creating a model to hold referrals, Referral. This will have the id of the referring account, the id of the referred account and the referral code used. Leavetrack allows trials without providing credit card information, so I know I will create a referral in the database when an account provides its credit card details i.e. I know they have signed up to a paying account.

class CreateReferrals < ActiveRecord::Migration
  def change
    create_table :referrals do |t|
      t.integer :referred_account_id, null: false
      t.integer :referring_account_id, null: false
      t.string :referral_code, null: false

      t.timestamps
    end
  end
end

Now we have the right model set up, it’s time to look at how we record the referral. Leavetrack has an update_card method which is used to pass card parameters to Stripe. What we will do is hook into this so that when a card is added, the referral is created:

def create_referral
  Referral.create(
    referred_account_id: @current_account.id,
    referring_account_id: @referring_account.id,
    referral_code: @referral_code
  )
  ApplyCoupon.call(@referring_account.id)
end

That final line is what we use to apply the coupon to the account of the referrer. I am a believer in moving anything that interacts with an external service to outside of the controller and model and into a service object.

class ApplyCoupon

  def self.call(referring_account_id)
    referral_hash = {
      1 => "ten",
      2 => "twenty",
      3 => "thirty",
      4 => "forty",
      5 => "fifty"
    }
    begin
      referring_account = Account.find(referring_account_id)
      referrals = Referral.where(referring_account_id: referring_account.id).where(referral_code: referring_account.referral_code)
      if referrals.length > 0
        customer = Stripe::Customer.retrieve(referring_account.stripe_customer_reference)
        subscription = customer.subscriptions.retrieve(referring_account.stripe_subscription.stripe_subscription_reference)
        referrals_count = referrals.length > 5 ? 5 : referrals.length
        subscription.coupon = referral_hash[referrals_count]
        subscription.save
      else
        Rails.logger.debug { "Apply Coupon - #donothing - #{referring_account_id}" }
      end
    rescue => e
      Rails.logger.debug { "#{e.inspect}" }
    end
    return [subscription, {success: true}]
  end

end

As noted at the start, the number of referrals determines the percentage reduction so we define a hash mapping the referral count to the id of a coupon in Stripe.

We then retrieve the subscription from Stripe and apply the correct coupon based on the number of referrals recorded in the database for the account.

I still have to implement removing coupons when accounts are cancelled but for the time being that’s not a concern for me.

If you have any questions, fire away.