LaunchSchool - An Online School for Developers /

Blog

Stripe Payments in Rails, Part 3 - Recurring Payments

This is the third article in the “Process Payments with Stripe in Rails” tutorial series:

In this post, we will work on the same code base for this tutorial series. We will implement a course subscription service to demonstrate recurring payment handling by Stripe.

We will work on the recurring branch:

1
2
3
4
5
6
7
8
git clone -b recurring git@github.com:gotealeaf/stripe-basics.git
cd stripe-basics
rake db:drop
rake db:create
rake db:migrate
rake db:seed
rails s
open http://localhost:3000

Make sure you have followed all the steps in Stripe Payments in Rails, Part 2 – Use Custom Forms with Stripe.js before continuing with the steps below.

Step 1. Modify our model to offer a subscription plan

Stripe’s recurring payment processing is implemented with the Plan concept. So first of all you need to create your plan in Stripe console > Plans:

Once we have our “all_courses” plan, we will add this plan info to our course model rails g migration add_plan_to_courses plan:string:

1
2
3
4
5
class AddPlanToCourses < ActiveRecord::Migration
  def change
    add_column :courses, :plan, :string
  end
end

Run migration rake db:migrate.

And running rails console rails c, create a course:

1
Course.create name: "ALL COURSES PLAN (monthly payment)", price: 95, plan: "all_courses"

Step 2. Sign up for the recurring payment plan

In registration model, add plan id when customer is created:

1
2
3
4
5
6
7
8
9
10
11
  def process_payment
    customer_data = {email: email, card: card_token}
                        .merge((course.plan.blank?)? {}: {plan: course.plan})
    customer = Stripe::Customer.create customer_data

    Stripe::Charge.create customer: customer.id,
                          amount: course.price * 100,
                          description: course.name,
                          currency: 'usd'

  end

Step 3. Create webhook to handle the monthly payment events

Every month Stripe will make an attemp to charge the card that the customer provided and notify us the result with a web hook (HTTP POST). On our side, we need to be able to update the user’s status accordingly. For our application, we will use an “end_date” column to capture when the user’s subscription is valid until, and increment that by 1 month every time the subscription payment goes through.

Add end date to Registration model

Run migrations generator rails g migration add_columns_to_registrations end_date:date customer_id:string:

1
2
3
4
5
6
class AddColumnsToRegistrations < ActiveRecord::Migration
  def change
    add_column :registrations, :end_date, :date
    add_column :registrations, :customer_id, :string
  end
end

Run migration rake db:migrate.

Annotate Customer Id when Registration is Created

Add to ‘models/registration.rb’, at the end of ‘process_payment’ method:

1
cusotmer_id = customer.id

Create hook resource

Add to your ‘config/routes.rb’ file:

1
post "registrations/hook"

Process the payment event

Add the following method to RegistrationsController

controllers/registrations_controller.rb

1
2
3
4
5
6
7
8
9
10
11
  # POST /registrations/hook
  protect_from_forgery except: :webhook
  def webhook
    event = Stripe::Event.retrieve(params["id"])

    case event.type
      when "invoice.payment_succeeded" #renew subscription
        Registration.find_by_customer_id(event.data.object.customer).renew
    end
    render status: :ok, json: "success"
  end

When the monthly payment is succeeded, just renew the registration.

Here, the “#renew” method is adding one month to the registration end date. Let’s add the following method to Registration model:

1
2
3
def renew
  update_attibute :end_date, Date.today + 1.month
end

Show registration attributes

Add in ‘views/registrations/show.html.haml’:

1
2
3
4
5
6
7
  %p
    %strong Customer Token:
    = @registration.customer_id
  - unless @registration.end_date.blank?
    %p
      %strong Plan End date:
      = @registration.end_date

Step 6. Testing the implementation

Expose our service to be accessed by Stripe

When we are running with the development mode, our webhook can not be accessed from Stripe to be tested directly because it is not exposed in the public internet, it is on our localhost.

We will use Ngrok to tunnel our local application to a Ngrok subdomain. We can then allow Stripe to send a HTTP POST to our localhost and test our payment process locally.

You can download Ngrok and install it for your system.

Now you can publish your application just running the command: ngrok 3000, since the rails port is 3000.

It will respond with a URL, http://1a74746e.ngrok.com in my case. You have to create the webhook into Stripe settings:

  1. Log in to your dashboard.
  2. Select your account name > Account Settings > Webhooks.
  3. Click Add URL and enter your webhook URL (http://1a74746e.ngrok.com/registrations/hook in my case). Indicate whether this is for live or test transactions.
  4. Click Create webhook URL.

Test this feature

Run the application, choose our new “ALL COURSES PLAN (monthly payment)”, fill the form (using dummy card number for test environment: 4242424242424242) and submit:

Now you have your registration successfully created with your ticket:

Give some time to let Stripe call our webhook, and refresh the ticket page. You have to see the Plan end date (just one month from today):

If you go to the Stripe console, you can see all events created with the subscription and the first payment:

You can also see the customer creation event details:

Conclusion

In this article we have showed you a basic example of setting up a recurring payment plan subscription. There are more options available if you have more sophiscated use cases. Check out the following Stripe documentation on recurring payments:

In the next tutorial – Stripe Payments in Rails, Part 4 – Plan Discounts with Coupons, we’ll look at how to add coupons to the payment plan.