Setting up Stripe Payments For Ruby On Rails

stripe logoI have used Stripe before for multiple projects. It is a great tool with an awesome API & documentation. I have to set it up again, but this time I figured I would document how I did it for my own sanity & so you can see just how easy it is. Any questions ask me in the comments, I’ll be happy to help anyone who needs a hand.

Is Stripe right for your business? Do you need to take credit card payments & don’t want to store that data?

This time it is for my own company QuickHire. The goal is to offer two plan levels, build a payment modal on our payment page, & allow employers to check out on their own. The modal part is important – the site will change often – so keeping all the spaghetti in one modal will make it easy to move around as you test payment pages.

Setup in Stripe Account

Okay so you have made my account on Stripe – it is in “Test” mode by default to enable sandbox development. Really nice feature that I wish more apps had – I usually just end up with two accounts – one to test and one I put in production. Facebook’s testing apps do a good job at this as well and deserve a shout out.

Screen Shot 2014-11-08 at 9.44.20 PMNext, I made my two levels of payment – Beta Monthly & Beta Yearly. This is found under the “Subscription” header on the “Plans” tab. These are currently being sold at a discounted rate to our normal & it is critical you keep in mind that you will need to be able to change plans in app frequently as you move forward. Also, I made a Coupon to use for testing that I want to have work when we go live for admin purposes.

Setup in App

First, I made a new branch in my git repo to work on payments – may not finish in one sitting.

High level actions that need to happen:

  1. Pull plans from Stripe
  2. Modal needs to display to the user with plan options
  3. User fills out form in app
  4. Data is sent to Stripe directly & returns a unique token
  5. Create a customer record in Stripe for the paying customer via API
  6. Store that customer token
  7. Make an API call to subscribe the user to there chosen plan
  8. Subscribe user in our database after a successful callback
  9. Thank user for subscribing
  10. Send a Slack notification to our #customers channel so we know what is happening as admins

Whew that’s a lot to do…oh well, I have all night.

Get the API connected!

To start with, grab the gem for bundler and put it in my Gemfile

gem 'stripe', :git => 'https://github.com/stripe/stripe-ruby'

Next you simply run in terminal in the project directory:

bundle install

Make the form work

Time to make that modal. I am just starting with a stock Bootstrap modal to make this as easy as possible. That will be rendered in my already existing payment page at the bottom. To test you will just auto trigger it on page load with sim javascript – great trick to save some time loading triggered modals that saves me so much time:

 $(function(){
   $("#stripePaymentModal").modal();
 });

With the modal in place you next have to build the charge form with will display the subscription options & request the customers details. The form details needed are well document by Stripe here. No use me copy/pasting a bunch of stuff. I’ll just cover any hickups & customization needed here.

First thing you might notice, is that you need to add the Plan Type the use want to pay for to the Stripe form.

<div class="form-row">
  <label>
   <span>Plan Type</span>
  </label>
  <%= select_tag :plan_type, options_for_select(
  [
   ["Monthly", "monthyl"],
   ["Yearly", "yearly"]
  ], params[:plan_type]), class: "form-control" %>
 </div>

This ideally will pull my plans and costs from Stripe and display them – for now I will hard code them – it’s late. You will notice that I am also using the Bootstrap form classes as well. I went ahead & added them to all the inputs, I also switched the layout to use the gird system from Bootstrap to make it look nice. I will stop talking about front end here – it would take forever as a will probably tweak the CSS forever after this. Here if what my testing form ended up looking like.

Screen Shot 2014-11-09 at 6.27.56 PM

However, when putting together your payment page I highly recommend you look for ways to make it clear how secure your solution is. Stripe provides a great way to keep your server clear of ever seeing a users card number. Philip Kaplan over at Distrokid has a great article about how conversion greatly hinged on the payment form design.

The JS used for the server tango

This is how my JS for the callback ended up looking. I kept it all in the modal partial to make sure you don’t have to worry about where you render it on the site later.

$(function(){
 $("#stripePaymentModal").modal();
  function stripeResponseHandler(status, response) {
  var $form = $('#payment-form');
  if (response.error) {
  // Show the errors on the form
  $form.find('.payment-errors').text(response.error.message);
  $form.find('button').prop('disabled', false);
  } else {
  // response contains id and card, which contains additional card details
  var token = response.id;
  // Insert the token into the form so it gets submitted to the server
  $form.append($('<input type="hidden"  name="stripeToken" />').val(token));
  // and submit
  $form.get(0).submit();
  }
 };
 jQuery(function($) {
 $('#payment-form').submit(function(event) {
 var $form = $(this);
 // Disable the submit button to prevent repeated clicks
 $form.find('button').prop('disabled', true);
 Stripe.card.createToken($form, stripeResponseHandler);
 // Prevent the form from submitting with the default action
 return false;
   });
  });
 Stripe.setPublishableKey('pk_test_GETYOUROWNKEYSILLY');
});

The form now submits and returns a unique token for me to use on my end to create a customer. Add the following to the routes file:

resources :employers, except: [:show, :new, :edit, :create] do
  collection do
   post "stripe_callback"
  end
 end

Create a customer & subscribe them

And now in the controller we need to take the submitted token and make the customer API call. Based on the API docs look like you can create a customer and subscribe them to a plan at the same time, awesome!

Here is what is currently capturing the returned token in the controller. It create a customer & subscribes them to the selected plan. Note that again none of the card info hits your server – avoid that big security no-no.

def stripe_callback
 @employer = current_employer #using Devise defaults
 if params[:stripeToken]
  require "stripe"
  Stripe.api_key = "sk_test_GETYOUROWNKEYSILLY"
  customer = Stripe::Customer.create(
   :description => "Beta Registration for a #{params[:plan_type]}",
   :card => params[:stripeToken], # obtained with Stripe.js
   :email => @employer.email,
   :plan => params[:plan_type]
  )
  @employer.update_attributes(subscribed: true, stripe_id: customer.id)
  redirect_to edit_profile_employers_path(active_tab: 'payment'), notice: "Thank you for subscribing!"
 else
  redirect_to edit_profile_employers_path(active_tab: 'payment'), alert: "Something went wrong!"
 end
end

Screen Shot 2014-11-10 at 12.05.20 PMThe key part in the above is to pass the subscription id within the customer creation call. The ID to use is found on the ‘Plans’ tab – click on the plan you want to look at and find the ID there. As I said before, ideally, we would pull the plans from Stripe dynamically & list them to make this more future proof, oh okay we will do that now, I have coffee anyway.

Backtracking – Pulling plan types from Stripe

Okay, so the basic idea is to call all plans and put them into the forms dropdown as an array, no problem. As usual the API is super easy to read.

This will go in the application_helper.rb so you can call it from anywhere in the app. Here you call all the plans, then loop through them and parse out the title to display – name & price – & the ID to use as the value. I use the ‘_for_select’ part on all form data sets I create to make it easier to remember how to get them.

def stripe_plans_for_select
 require "stripe"
 Stripe.api_key = "sk_test_GETYOUROWNKEYSILLY"
 data = []
 plans = Stripe::Plan.all
 plans.data.each do |plan|
  data << ["#{plan.name} $#{plan.amount/100}", plan.id]
 end
 return data
end

And update the select form to use the new data & we are all set.

<%= select_tag :plan_type, options_for_select(stripe_plans_for_select, params[:plan_type]), class: "form-control" %>

Display employers subscription info

Finally, you will want to show your customer their subscription info somewhere so that they know what is happening billing wise. For now the basic info will be enough on our account page to let the customer know when they will be billed next and what plan they are on.

In the controller for our profile page you want to pull the subscription data for the customer.

if @employer.subscribed? && @employer.stripe_id != nil && @employer.stripe_id != ''
 require "stripe"
 Stripe.api_key = "sk_test_GETYOUROWNKEYSILLY"
 @customer = Stripe::Customer.retrieve(@employer.stripe_id)
 @subscription = @customer.subscriptions.data.first
end

Then on the front end we render out the basic details.

<% if @employer.subscribed? && @employer.stripe_id != nil && @employer.stripe_id != '' %>
 <h3>Subscription Info</h3>
 <p><%= @subscription.plan.name %> $<%= @subscription.plan.amount/100 %></p>
 <p>Next invoice to be sent on <strong><%= Time.at(@subscription.current_period_end).to_datetime.strftime("%B %d %Y") %></strong></p>
 <p><small>Want to cancel your subscription? No problem, just give us a call: 555-5555</small></p>
 <hr>
<% end %>

Screen Shot 2014-11-10 at 2.00.26 PMThis will give the customer the bare-bones info about when they can expect another invoice & what plan they are on. For now we won’t include how to change plans, that will be another update.

Send admin notification to Slack

Slack is an amazing tool. I recommend everyone uses it – I’ll write a review on this at some point. For now we will be using their webhook API to send ourselves a notification about who subscribed (using the webhook will be its own guide – some day – for now just a shoutout to the library we use: Slack Poster).

I added this to the stripe_callback function in my controller.

# SEND SLACK NOTIFICATION
message = '#{@employer.username} from #{@employer.company_name} just signed up for a #{params[:plan_type]} subscription! WooHoo!'
 team = 'QuickHire'
 token = 'GETYOUROWNTOKENSILLY'
 options = {
 icon_url: @employer.profile_photo('small'),
 username: "NEW SUBSCRIPTION - #{@employer.username}",
 channel: '#customers'
}

This is what the final output looks like in out chat channel. This is a key way we decide how to respond to customers & support – everyone can see updates and quickly decide who/when/if we need to take action.

Screen Shot 2014-11-10 at 3.10.48 PM

chair wiggle

Now the whole team can see when we have a new paying customer and do a mini victory dance, slap some high fives, or wiggle a little in their chair.

Why don’t we use the official Stripe integration for Slack?

Good question – this gives us more control over what is communicated to our team, keeps it simple. The Slack Poster gem is so easy to use we have it all over our site, very familiar with it’s options. Also, it keeps our number of integrations for Slack down under the paid limit – we are small, free is good. I promise Slack we will pay when we expand our team.

Switching it to LIVE!

You have it all setup and working in our development environment, great. But we need to add our production keys and allow it to stay in test mode on our staging servers – what should you do?

I use dotenv to manage my server environment variables – read: secret keys (another tutorial). So the code for development detection is fairly simple. In each instance we need a key, I simply use this if statement.

if Rails.env.development? || (ENV["STAGING"] && ENV["STAGING"] == "true")
 Stripe.api_key = "sk_test_GETYOUROWNKEYSILLY"
else
 Stripe.api_key = ENV["STRIPE_SECRET_KEY"]
end

Just check the environment – on my staging server I have an ENV variable to declare this – and then setup your environment variables as normal on production. KISS

Conclusion

So we have a dynamic form for customers to signup for subscriptions with that offers a great deal of security, can subscribe new customers, & can show customers their billing info! Next steps would be to clean up the form and make it a little more secure feeling, auto select plan types in the form based on what is selected on our plan’s page (monthly or yearly), & setup our production keys with Stripe for staging & production servers.

Think Stripe is awesome? Me too. What tools are you using to track payment actions for your app?

Leave a Reply

Your email address will not be published. Required fields are marked *