
Basic Stripe subscription implementation in Rails 4/5.
Written by a beginner, for beginners.
Hi everyone, I’m very much a beginner at Ruby and Rails, but I’m loving every minute of it. As a novice, I quite often run into walls and problems, so I’d like to start posting my solutions to help others like me.
In this guide, I’ll show you how to set up a simple app that allows users to pay and sign up to a subscription plan. To achieve this, we will make use of the Stripe and Devise gems.
If at any point you get stuck, you can refer to the code here: https://github.com/Blandee/stripe-rails-demo
Warning: The app we’re about to build doesn’t make a lick of sense, but it serves its purpose of demonstration.
Setup
First things first, let’s generate the Rails app. In your terminal, in your preferred directory, run:
$ rails new stripe_demo
When that’s done, don’t forget to cd into the app directory and install all the dependencies:
$ bundle install
For the sake of time, and for the purpose of rapid prototyping, we’re going to generate a scaffold to get this app up and running pronto:
$ rails g scaffold product name:string price:integer
Great! You should have a very simple Rails app now, that allows you to create, edit, update and delete products using simple CRUD actions. Start up your server to view it:
$ rails s
Since we haven’t set a homepage yet, head over to http://localhost:3000/products to view the app.
Devise
Unlike one off payments, when you’re selling periodic subscriptions to customers, it’s always a good idea for there to be a user in which you can assign the subscription too. That way, you can query it at a later date, such as if they want to update or change their subscription.
For this reason, we’re going to use Devise to create our user models and tables, as well as add authentication into our app.
First, add this line to your gemfile:
gem 'devise'
Next, run this command in your terminal to install Devise:
$ rails generate devise:install
Once you’ve run this, you will be presented with some instructions in your terminal to complete, in order to finish setting up Devise. For step 2, set “home/index” as your root (which we’ll create later), in ‘config/routes.rb’:
root "home#index"
Next, we’ll generate the user model and schema:
$ rails generate devise User
Don’t forget to migrate your database afterwards:
# For Rails 4
$ rake db:migrate
# For Rails 5
$ rails db:migrate
The final step here is to set up a very basic sign up/sign in page. First, let’s generate it:
$ rails g controller home index
When that has finished, navigate to the home controller (app/controllers/home_controller.rb), and enter this code in:
def index
if user_signed_in?
redirect_to :controller => ‘products’, :action => ‘index’
end
end
What we’re doing here is making use of Devise’s very handy helpers. The helper ‘user_signed_in?’ will detect whether the current user is signed in, and if they are, it will redirect them to the products page.
Next, open ‘product_controller.rb’, and write this at the top:
before_filter :authenticate_user!
This is a helpful filter that Devise provides. It will prevent any user who is not signed in from visiting the products page and instead redirect them to the sign up/sign in page.
Finally, in your ‘views’ folder, under ‘home’, create a new file and call it ‘index.html.erb’. Inside the file, add these two links:
<p><%= link_to ‘Log in’, new_user_session_path %></p>
<p><%= link_to ‘Sign up’, new_user_registration_path %></p>
Great job! You now have a simple, but functional, user authentication system for your app.
You can also add a ‘Sign out’ link to the product’s ‘index’ page, to make the process more complete:
<p><%= link_to ‘Sign out’, destroy_user_session_path, :method => :delete %></p>
Stripe
Phew! You’re doing well so far. But this is the real reason you’re here, isn’t it? Well then, let’s crack on!
In order to get started using Stripe’s wonderful API in our app, we’ll first need to add it to our gemfile (don’t forget to run ‘bundle install’ afterwards!):
gem ‘stripe’, :git => ‘https://github.com/stripe/stripe-ruby'
Configuring Stripe
Before we can start tampering with our views and controllers, there’s a bit of configuration we need to do first.
First things first, you’ll need to head over to https://stripe.com/ and create an account. Once you’re finished, open up your dashboard. Hover over your account name in the top right corner, and click ‘Account Settings’. Mosey on over to the tab named ‘API keys’, and take note of what is in there. We’ll be coming back to them in just a second.
Back in your Rails app, open up the ‘config’ folder and create a new file called ‘stripe.rb’ inside the ‘initializers’ folder. Write this inside:
Rails.configuration.stripe = {
:publishable_key => Rails.application.secrets.stripe_publishable_key,
:secret_key => Rails.application.secrets.stripe_secret_key
} Stripe.api_key = Rails.application.secrets.stripe_secret_key
For the purpose of this demo, we’re going to only be using our test API keys that we found in our dashboard. Place them inside your ‘secrets.yml’ file:
development:
stripe_publishable_key: pk_test_xxxxxxxxxxxxxxxxxxxxxxxxx
stripe_secret_key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxxx
Next step is to create a subscription plan. Back in your Stripe dashboard, head over to the plans section (on the left), and create a new plan. Make sure to give your plan an id, name and price.
The final step in our configuration is to add some new columns to our user schema. Since each user might now be signing up to a subscription, we’ll want to assign them a Stripe ID, as well as check whether they are subscribed or not.
To do this, in your terminal, generate a new migration:
$ rails g migration AddStripeToUsers
This will create a new migration file inside your ‘db/migrate’ folder. Open it up and write this inside:
class AddStripeToUser < ActiveRecord::Migration[5.0]
def change
add_column :users, :subscribed, :boolean, :default => false
add_column :users, :stripeid, :string
end
end
Don’t forget to run a migration afterwards!
Creating the recurring payment
Almost there, promise! Now the configuration is all done, let’s go ahead and get stuck in with the views and controllers.
First, let’s generate the subscription controller first:
$ rails g controller subscribe new
Before we rush off, let’s not forget to add the subscribe controller to our routes, so the system is aware of all its paths. Inside your ‘routes.rb’ file, add:
resources :subscribe
Adding the subscription functionality
Inside the controller, we want to set up the code that will handle the transaction and submit the stripe data to our updated user table. It should look like this:
class SubscribeController < ApplicationController
before_filter :authenticate_user!
def new
end
def update
# Get the credit card details submitted by the form
token = params[:stripeToken]
# Create a Customer
customer = Stripe::Customer.create(
:source => token,
:plan => # Your plan ID,
:email => current_user.email
)
# Save stripe information to the current user using Devise
helper
current_user.subscribed = true
current_user.stripeid = customer.id
current_user.save
# Redirect back to products page with a ‘success’ notice
redirect_to products_path, :notice => “Your subscription was
successful!”
end
end
What are we doing here?
- We’re checking to see if the user is authenticated, if not, send them back to the sign up/log in page.
- We’re getting the credit card details from the form entry (which we’ll implement next) and submitting it to our Stripe account.
- We’re creating a customer in our stripe account and assigning their card details, their plan’s ID and their email.
- We’re then updating our user table with the new stripe data.
- Finally, if all was successful, we’re redirecting our users back to the products page with a ‘success’ message!
Adding the checkout form
Finally, we’ll add the payment gateway for our subscription, which will gather the user’s details. Head over to the newly generated ‘new.html.erb’ file in ‘views/subscribe’, and write this in:
<%= form_tag subscribe_path(1), :method => :put do %>
<article>
<label class=”amount”>
<span>Subscribe to Plan 1: £30.00</span>
</label>
</article>
<script src=”https://checkout.stripe.com/checkout.js"
class=”stripe-button” data-key=”<%=
Rails.configuration.stripe[:publishable_key] %>”
data-description=”A month’s subscription”
data-amount=”3000"
data-locale=”auto”>
</script> <p>
<%= link_to ‘Back’, products_path %></p>
<% end %>
Let’s break this down:
- Firstly, we’re creating a form tag. Since we’ll be using the ‘update’ function in the controller to complete the transaction, we need to provide it with an ID by default. So we’re doing a bit of a cheat here, by providing it with the ID of 1, but it can be any number (taken from Mike Hibbert).
- Next, we’ve got a bit of static html describing the product.
- Finally, we’re generating a checkout button using a <script> tag from Stripe. We’re also entering in some meta data about the subscription. It will work out the subscription plan in question by the ID you passed in the controller — clever stuff!
Before we can test this out, add this line to your product’s ‘show.html.erb’ file, so we have a way of accessing the subscription checkout:
<p><%= link_to ‘Subscribe’, new_subscribe_path %></p>
Note: In order to see this, you’ll need to have created at least one product.
Finished!
Whew! Take a deep breath and give yourself a pat on the back, because we’re finished! If all has gone well, you should have a simple little app, that allows for users to sign up, sign in, create a product and then subscribe to it! (Admittedly, it doesn’t make sense…)
Check the ‘Customers’ section in your Stripe dashboard, and you should have the account you created in devise as a newly added customer. Moreover, if you check your user table in your rails console, you should see that the account now has their stripe ID applied and the subscription boolean set to true.
Hooray! Cheers to us!
BONUS: How to implement multiple subscription plans.
So you’ve made it this far, but you want to take it one step further. What if you have more than just one subscription plan? How can you display them, as well as handle multiple plans in the controller?
To add this functionality to the app we made is quick and simple, so stick with me, and we’ll be finished in no time!
A bit more configuration
This upgrade requires a bit more set up on our side. First things first, head to your Stripe dashboard and set up a few more plans.
Once you’ve done that, we’ll need to make a new migration to our user table. We want to add the plan’s ID to the user, so we know who is subscribed to which plan. You know the drill:
$ rails g migration AddPlanIdToUser
Inside the newly generated migration folder, let’s add the new column:
class AddPlanIdToUser < ActiveRecord::Migration[5.0]
def change
add_column :users, :planid, :string
end
end
Don’t forget to run a db:migrate!
Displaying the plans in the view
Now, we want to display all our plans in the view, right? So, let’s head over to the subscribe controller and add an index function at the top of the page:
def index
@stripe_list = Stripe::Plan.all
@plans = @stripe_list[:data]
end
This will store all our plans in an instance variable, which we can access in the view. Let’s create that now. Inside ‘views/subscribe’, create an ‘index.html.erb’ file. Inside it, we’ll add a simple loop that gets and displays each plan:
<%= form_tag subscribe_path(1), :method => :put do %>
<% @plans.each do |plan| %>
<div class=”plan”>
<h1><%= plan[:name] %></h1>
<p>£<%= plan[:amount]/100 %></p>
<%= form_tag(‘/new’, {method: :post, plan: plan}) do %>
<input name=”plan_id” type=”hidden” value=”<%= plan[:id] %>”>
</input>
<% end %><script src=”https://checkout.stripe.com/checkout.js"
class=”stripe-button”
data-key=”<%= Rails.configuration.stripe[:publishable_key] %>”
data-description=”A month’s subscription”
data-amount= (plan[:amount])
data-locale=”auto”></script>
</div>
<% end %>
<% end %>
Let’s break this down:
- We’re taking the same form tag that we used before.
- We’re making a simple loop that accesses the instance variable that we created in the controller and outputting each plan.
- For each plan, we’re displaying its name, price and stripe’s checkout button.
- We’re also outputting the plan’s ID in a hidden form tag, for the controller to reference.
Easy as pie!
Update the controller
All that’s left to do now is modify the controller’s ‘update’ function to handle multiple subscriptions. Inside the update function, write this underneath the ‘token’ variable:
plan_id = params[:plan_id]
plan = Stripe::Plan.retrieve(plan_id)
This will retrieve the specific plan ID that the user is signing up for and store them in variables.
Secondly, switch out the hard coded plan ID for the plan variable:
customer = Stripe::Customer.create(
:source => token,
:plan => plan,
:email => current_user.email
)
Finally, save the plan’s ID to the user table:
current_user.planid = plan_id
Finished… Again!
And you’re done! If all went according to plan, you should now be able to view all your plans, as well as subscribe to one.
I added this link to my product’s ‘index.html.erb’ in order to access the list view:
<p><%= link_to ‘See all plans’, subscribe_index_path %></p>
Again, if you check both your Stripe dashboard and your users in the rail console, you should see the new data reflected.
That’s it for now. Thank you for reading this lengthy tutorial. I tried to make it as simple and straight forward as possible, to help other beginners like me.
Until next time!
Further Resources
- Reference code — https://github.com/Blandee/stripe-rails-demo
- Stripe documentation — https://stripe.com/docs
- Devise gem— https://github.com/plataformatec/devise
- Stripe gem — https://github.com/stripe/stripe-ruby
- Vasu K’s guide on Stripe subscription in Rails — http://www.sitepoint.com/stripe-subscriptions-rails/
- Mike Hibbert’s guide on Stripe payment handling in Rails — https://www.youtube.com/watch?v=kp-9Ac5wTxY