Ruby on Rails 5 with Stripe Element Integration

This tutorial shows you how I set up Stripe Element with Ruby on Rails 5 for my project For A Piece, a job board for programmers looking for companies that offer equity. 


This project is using Ruby 2.6.1 and Rails 5.2.3. This tutorial expects you to have an initial Rails app. If you’re copying&pasting, you might need to update the quotes.

Step 1.

Add gem 'stripe' to your gemfile and bundle install.

Step 2.

Add the code to your application.html.erb. I’ve added this inside the <header></header> section after <%= yield :javascript %>. I’ve added 2 environments as I do not wish to charge a real card during development. You’re going to see if/else in Step 2 and Step 3. This isn’t required and you can choose how to set up your own environment.

<%= yield :javascript %>
<%= yield :head %>
<%= javascript_include_tag 'application', "", "", 'data-turbolinks-track': 'reload' %>

<% if Rails.env == 'development' %>
    <%= tag :meta, name: "stripe-public-key", content: Rails.application.credentials.stripe_test[:publishable_key] %>
<% else %>
    <%= tag :meta, name: "stripe-public-key", content: Rails.application.credentials.stripe_production[:publishable_key] %>
<% end %>

Step 3.

Initialize stripe.rb. Create a file config/initializers/stripe.rb 

require "stripe"

if Rails.env == 'development'
  Rails.configuration.stripe = {
    :publishable_key => Rails.application.credentials.stripe_test[:publishable_key],
    :secret_key      => Rails.application.credentials.stripe_test[:secret_key]
  Stripe.api_key = Rails.application.credentials.stripe_test[:secret_key]
  Rails.configuration.stripe = {
    :publishable_key => Rails.application.credentials.stripe_production[:publishable_key],
    :secret_key      => Rails.application.credentials.stripe_production[:secret_key]
  Stripe.api_key = Rails.application.credentials.stripe_production[:secret_key]

Step 4.

Add Routes, Controller, and View. I chose Purchases, but you can call this any name that makes sense to you. 

In the routes.rb add resources: purchases, only: [:new, :create]

In the purchases_controller.rb add

class PurchasesController < ApplicationController
  def new

  def create
    token = params[:stripeToken]
    if token
        amount: '100.00',
        currency: "usd",
        description: 'your product description',
        source: token
      flash[:alert] = 'Something went wrong with your payment. Please try again later'
      render 'new'

In views/purchases/new.html.erb add

<%= form_tag purchases_path, id: "payment-form" do |form| %>
<div class="group">
<input id="name" class="field" placeholder="Jane Doe" />
<div id="card-element" class="field"></div>
<button class='subscription-button'>Place your order</button>
<div class="outcome">
<div id="card-errors" role="alert"></div>
<div class="success">
Success! Your Stripe token is <span class="token"></span>
<% end %>

Step 5

The final piece of the puzzle. Adding Javascript to stylize, embed, and submit the form. In the path assets/javascripts/subscriptions.js add

document.addEventListener("turbolinks:load", function() {
  var public_key = document.querySelector("meta[name='stripe-public-key']").content;
  var stripe = Stripe(public_key);
  var elements = stripe.elements();

// Custom styling can be passed to options when creating an Element.
  var style = {
    base: {
      // Add your base input styles here. For example:
      fontSize: '18px',

 // Create an instance of the card Element
  var card = elements.create('card', {style: style});
 // Add an instance of the card Element into the `card-element` <div>
  // card.mount('#example1-card');
 card.addEventListener('change', function(event) {
    var displayError = document.getElementById('card-errors');
    if (event.error) {
      displayError.textContent = event.error.message;
    } else {
      displayError.textContent = '';
  // Create a token or display an error when the form is submitted.
  var form = document.getElementById('payment-form');
  form.addEventListener('submit', function(event) {
    var name = document.getElementById('name').value;
    if (!name) {
      var errorElement = document.getElementById('card-errors');
      errorElement.textContent = "You must enter a name.";
    } else {
      var options = {
        name: name,
 stripe.createToken(card, options).then(function(result) {
        if (result.error) {
          // Inform the user if there was an error
          var errorElement = document.getElementById('card-errors');
          errorElement.textContent = result.error.message;
        } else {
          // Send the token to your server
 function stripeTokenHandler(token) {
  // Insert the token ID into the form so it gets submitted to the server
  var form = document.getElementById('payment-form');
  var hiddenInput = document.createElement('input');
  hiddenInput.setAttribute('type', 'hidden');
  hiddenInput.setAttribute('name', 'stripeToken');
 ["brand", "exp_month", "exp_year", "last4"].forEach(function(field) {
    addFieldToForm(form, token, field);
 // Submit the form
 function addFieldToForm(form, token, field) {
  var hiddenInput = document.createElement('input');
  hiddenInput.setAttribute('type', 'hidden');
  hiddenInput.setAttribute('name', "user[card_" + field + "]");
  hiddenInput.setAttribute('value', token.card[field]);

That’s all folks! Now when you visit purchases#new you will see a form with a name and credit card field that is already styled right on your page. No more ugly modals! 

If you’re looking for a new remote programming job that offers equity come checkout For A Piece, it’s free! 

John Moon