Integrate Stripe in your Ruby on Rails app
Tags: ruby, rails, stripe
Published: 2019-03-20 14:14:34

---
title: Integrate Stripe in your Ruby on Rails app
published: true
description: Stripe is a very good platform to manage payments on your website. It's very easy to use and integrate. In this article we will integrate Stripe on a Ruby on Rails application. 
tags: ruby, rails, stripe
cover_image: https://thepracticaldev.s3.amazonaws.com/i/3pgzz9z1ksn70wu84mc1.png
---
## Creating a workspace
We will start by creating a Ruby on Rails application
```
$ rails new tuto
$ cd tuto
$ bundle install
```
Then, we will generate a controller named Billing with the help of ```rails generate```
```
$ rails generate controller Billing

```

After that, we're going to add route in _config/routes.rb_ :
```ruby
root 'billing#index', as: :billing 
```

To finish, we have to create an empty action index in _app/controllers/billing_controller.rb_:
```ruby
class BillingController < ApplicationController

  def index
  end
  
end
```

In _app/views/billing_ we will create a file index.html.erb where we will add a button that will show the "Stripe Checkout" modal, that will let us link a credit card to a user. For this tutorial I will be using (as always) the bootstrap library. If you want to use it too, don't forget to add it in your app. If you want to learn how to do it, you can read [this article](https://medium.freecodecamp.org/add-bootstrap-to-your-ruby-on-rails-project-8d76d70d0e3b). So in _app/views/billing/index.html.erb_:
```html
<div class="container">
  <div class="row">
    <h1 class="col-md-12 mt-5 text-center">
      Are you ready to pay?
    </h1>
  </div>
  <div class="row">
    <div class="col-md-12 mt-4 text-center">
      <button class="btn btn-primary">Let's go </button>
    </div>
  </div>
</div>
```

For now, we will leave our button like this and later we will change it using a Rails syntax.

## Creating a User with Devise
Now, we will implement basic authentication with the help of the "devise" gem. We want only connected users to be able to access the billing page. Start by adding the following line in your _Gemfile_: 
```ruby
gem 'devise'
```

To setup devise we have to type this in the terminal:
```
$ bundle install
$ rails g devise:install
```


After running these two commands, the terminal will display instructions to configure devise. It says that we have to add this line of code in _config/environments/development.rb_:
```ruby
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```

The next step is to create a User model: 
```
$ rails g devise User
$ rails db:migrate
```

That's it. We added authentication with devise. Now we are ready to create our first user.  We need to run 'rails s' in terminal and go to the following page: localhost:3000/users/sign_up. After we created the account it will redirect us automatically to the root page at localhost:3000.

We now want that only signed-in users have access to localhost:3000. For this in _app/controllers/billing_conroller.rb_ we need to add:
```ruby
class BillingController < ApplicationController
  before_action :authenticate_user!

  def index
   @user=current_user.email
  end
  
end
```

So before any action in billing controller it will check if user is signed in. Also in the index action I added a global variable @user which takes email of current user. I will use it in _app/views/billing/index.html.erb_:
```html
<div class="container">
  <div class="row">
    <div class="col-md-12 mt-4 text-center">
      <h1> Welcome  <%= @user %></h1>
    </div>
  </div>
  <div class="row">
    <h2 class="col-md-12 mt-5 text-center">
      Are you ready to pay?
    </h2>
  </div>
  <div class="row">
    <div class="col-md-12 mt-4 text-center">
      <button class="btn btn-primary">Let's go </button>
    </div>
  </div>
</div>
```

To check if everything works we will go to localhost:3000 and clear our cookies. After refreshing page you should be automatically redirected to the Sign in page.
 
## Integrating Stripe

### Adding the Stripe credentials

Firstly, you have to sign up on Stripe.
Then, you can find the development and production keys for Stripe on your dashboard, under __developers => API keys__. The keys that you will see now are for production. To see development keys click to __'view testing data'__.
![alt text](https://thepracticaldev.s3.amazonaws.com/i/zhx43ftdoei1u36otcwu.png "Stripe dashboard")


Now we will add the keys to the rails encrypted credentials. To do this, I use the GNU nano editor which is installed by default on MacOS and Linux.
``` $ EDITOR=nano rails credentials:edit ```

![alt text](https://thepracticaldev.s3.amazonaws.com/i/21dkny3ugee7r0l7xq8t.png
 "Nano editor")

Here we add our keys for development and production.
```
stripe:
  development:
    publishable_key: 'pk_test_...'
    secret_key: 'sk_test_...'
  production:
    publishable_key: 'pk_live_...'
    secret_key: 'sk_live_...'

```
 
### Installing Stripe

You need also to add the stripe checkout javascript in _app/views/layouts/application.html.erb_:

```ruby
<%= javascript_include_tag 'https://checkout.stripe.com/checkout.js' %>
```

Also in _config/enviroments/development.rb_ we add: 
```ruby 
config.stripe.secret_key = Rails.application.credentials.stripe[:development][:secret_key]
config.stripe.publishable_key = Rails.application.credentials.stripe[:development][:publishable_key]
```

And in _config/enviroments/production.rb_:
```ruby
config.stripe.secret_key = Rails.application.credentials.stripe[:production][:secret_key]
config.stripe.publishable_key = Rails.application.credentials.stripe[:production][:publishable_key]
``` 
Finally, we will add the stripe gem in our _Gemfile_
```ruby
gem 'stripe-rails'
```

And run 'bundle install' in terminal.

### Setting up the route

Now we are returning to _config/routes.rb_ and add to the file: 
```ruby 
get '/card/new' => 'billing#new_card', as: :add_payment_method`
```

### Linking a card to a user

In _app/controllers/billing_controller.rb_ we are creating new action: 
```ruby
def new_card
    respond_to do |format|
      format.js
    end
  end
```

It sends us to _new_card.js.erb_ which we will create in _app/views/billing_. So in _app/views/billing/new_card.js.erb_ :
```javascript
var handler = StripeCheckout.configure({
    key: '<%= Rails.application.credentials.stripe[Rails.env.to_sym][:publishable_key] %>',
    //get a publishable key that we put in editor depending on environment: production or development
    locale: 'auto',
    //handle translation
    name: "upload.express",
    description: "Add your credit card information",
    email: "<%= current_user.email %>",
    panelLabel: "Add payment method",
    allowRememberMe: false,
    token: function (token) {
        var form = document.getElementById('billing-create-payment-method');
        //we will create element with this id in the next step
        var hiddenInput = document.createElement('input');
        hiddenInput.setAttribute('type', 'hidden');
        hiddenInput.setAttribute('name', 'stripeToken');
        hiddenInput.setAttribute('value', token.id);
        //creating an <input type="hidden" name="stripeToken" value="<id>"/>. We will need this information in the next steps to link a user to his card 
        form.appendChild(hiddenInput);
        //adding this input when we use a form.
        form.submit();
    }
});

handler.open();

window.addEventListener('popstate', function() {
    handler.close();
});
```

Then we change our button in _app/views/billing/index.html.erb_ into a form with id "billing-create-payment-method":
```ruby
<%= form_tag id: "billing-create-payment-method" do  %>
        <%= link_to "Let's go", add_payment_method_path, remote: true, class: "btn btn-primary" %>
      <% end %>
```

After that in terminal we run 'rails s' and after clicking on our button we should have something like this: 
![alt text](https://thepracticaldev.s3.amazonaws.com/i/7qtebr3t26ncx6e0lty9.png "Almost there!")


Almost there! Now we need to associate the current user to the given card. To do this we have to add a new column stripe_id of type string in the User model by running this in terminal:
```
$ rails g migration AddStripeIdToUsers stripe_id:string
$ rails db:migrate
``` 

In _config/routes.rb_ we are creating a new route:
```ruby
post "/card" => "billing#create_card", as: :create_payment_method
```

Now in controller in _app/controllers/billing_controller.rb_ we are creating action create_card: 
```ruby
def create_card 
    respond_to do |format|
      if current_user.stripe_id.nil?
        customer = Stripe::Customer.create({"email": current_user.email}) 
        #here we are creating a stripe customer with the help of the Stripe library and pass as parameter email. 
        current_user.update(:stripe_id => customer.id)
        #we are updating current_user and giving to it stripe_id which is equal to id of customer on Stripe
      end

      card_token = params[:stripeToken]
      #it's the stripeToken that we added in the hidden input
      if card_token.nil?
        format.html { redirect_to billing_path, error: "Oops"}
      end
      #checking if a card was giving.

      customer = Stripe::Customer.new current_user.stripe_id
      customer.source = card_token
      #we're attaching the card to the stripe customer
      customer.save

      format.html { redirect_to success_path }
    end
  end
```

We are changing a bit our _app/views/billing/index.html.erb_ in order to call an action create_card when we submit our form.

```ruby
<%= form_tag create_payment_method_path, id: "billing-create-payment-method" do  %>
        <%= link_to "Let's go", add_payment_method_path, remote: true, class: "btn btn-primary" %>
      <% end %>
```

Quickly, we are going to add the success page. Create a route, empty action and view. 

In _config/routes.rb_:
```rails
get '/success' => 'billing#success', as: :success
```

In _app/controllers/billing_controller.rb_:
```ruby
def success
end
```

In _app/views/billing/success.html.erb_:
```html 
<div class="container">
  <div class="row">
    <div class="col-md-12 mt-4 text-center">
      <h2>You successfully linked a credit card to your account</h2>
    </div>
  </div>
</div>
```

Now run in terminal 'rails s'. Click on 'Let's go' on the website. For testing purposes you can use the card 4242 4242 4242 4242 with random CVC code and date. After submitting we should be redirected to our success page. And if we go on Stripe in __Customers__ (don't forget to switch to test data) we should see an email and card info of our user.
![alt text](https://thepracticaldev.s3.amazonaws.com/i/stf0tq7uh02dlpf35z3g.png "Stripe -> Customers")

Now we need make customers to actually pay after registering a card. It means that we have to subscribe our customer.

## Subscription

First, we need to create a product. The easiest ways to do it is through the Stripe dashboard. Then, we will attach 2 pricing plans to the product. For example in our product upload.express you can pay 7€ per month, or you can subscribe yearly for 60€. We need to go to our __Stripe dashboard => Billing => Products__ and click on the button __"New"__. Create your product with 2 pricing plan. I suggest you to choose explicit definition like "monthly" and "yearly" for your pricing plan nickname. If you add a yearly plan, don't forget to set the interval on 'yearly'. To add a pricing plan, you need to click on the product you just created and then click on the button __"add a pricing plan"__. 
 
Now we want to fetch the pricing plans we created in our application. We will be doing it on our page "success". So in _app/controllers/billing_controller.rb_ in success: 
```ruby
def success
    @plans = Stripe::Plan.list.data
  end
```

Now we need to subscribe our user to the plan that he will choose. So we need to create a new action which will link our customer to the plan and create a subscription.

In _config/root.rb_: 
```ruby
post '/subscription' => 'billing#subscribe', as: :subscribe
```

In _app/views/billing/success.html.erb_ we add:
```html
<div class="row">
  <div class="col-md-12 mt-3 text-center">
    <h3>Now you need to choose your plan</h3>
  </div>
</div>
<!-- creating a form -->
<%=form_tag subscribe_path, method: :post do %>
<div class="row">
  <div class="col-md-4"></div>
  <div class="col-md-4 text-center">
    <div class="form-group">
      <select class="form-control" name="plan_id">
        <% @plans.each do |plan| %>
        <option value="<%= plan.id %>"><%= plan.amount/100 %>/€ <%= plan.nickname %></option>
        <!-- we pass id chosen by custmer as a value  to use it for subscription -->
        <%end%>
      </select>
    </div>
  </div>
  <div class="col-md-4"></div>
</div>
<div class="row">
  <div class="col-md-12 mt-2 text-center">
    <%= submit_tag 'Save changes', class: "btn btn-primary" %>
  </div>
</div>
<% end %>
```

In _app/controllers/billnig_controller.rb_:
```ruby
def subscribe
      if current_user.stripe_id.nil?
        redirect_to success_path, :flash => {:error => 'Firstly you need to enter your card'}
        return
      end
      #if there is no card
      
      customer = Stripe::Customer.new current_user.stripe_id
      #we define our customer

      subscriptions = Stripe::Subscription.list(customer: customer.id)
      subscriptions.each do |subscription|
        subscription.delete
      end
      #we delete all subscription that the customer has. We do this because we don't want that our customer to have multiple subscriptions

      plan_id = params[:plan_id]
      subscription = Stripe::Subscription.create({
                                                     customer: customer,
                                                     items: [{plan: plan_id}], })
   #we are creating a new subscription with the plan_id we took from our form
                                                     
      subscription.save
      redirect_to success_path
    end
  end
```

It's ready. Now we will check our app. Choose a pricing plan, submitting it.
To check everything worked, go to Stripe, __Dashboard => Billing => Subscriptions__. Our subscription should be here. If you change your plan and take a look at Stripe, the subscription should change as well.
 
That's it. You integrated Stripe on your Rails app. Congratulations!!!

P.S. It's my first technical article, I hope it was understandable and you enjoyed it!