Integrating Recurring Payments to Your Rails API With Stripe | by Bruno Feres

Cowl

For this utility, I’ll think about you have already got a Consumer’s mannequin in your utility. In case you don’t have it but, don’t fear! I already printed an article about that, you possibly can read it here.

Should you adopted the steps of my different article, to create your Consumer mannequin, or just cloned it from GitHub, you will want to vary the Ruby model on the Gemfile. For this text, I shall be utilizing Ruby 3.0.0, so your Gemfile should seem like that:

supply 'https://rubygems.org'
git_source(:github) repo
ruby '3.0.0'...

Additionally, add the Stripe Gem to your Gemfile.

gem 'stripe'

Don’t overlook to run bundle set up in your terminal after that.

Now you will want to create a stripe initializer file in your utility. For that, run the command under in your terminal:

contact config/initializers/stripe.rb

Then, open the stripe.rb file and write the content material under:

Stripe.api_key = Rails.utility.credentials.stripe_secret_key

We didn’t add that Stripe’s secret key in our credential file, so let’s do that.

To open your credential file, run in your terminal:

EDITOR=nano rails credentials:edit

Get your Stripe Secret Key here.

Your credential file should seem like this:

# aws:
# access_key_id: 123
# secret_access_key: 345
# Used as the bottom secret for all MessageVerifiers in Rails, together with the one defending cookies.
secret_key_base: [YOUR SECRET KEY BASE]
stripe_secret_key: [YOUR SECRET KEY HERE]

Notice that the secret_key_base is autogenerated, you don’t have to edit.

To begin with, we’d like our customers to have a Stripe Buyer ID. We have to retailer that ID in our database, so run the command under to create a migration:

rails g migration AddStripeIdToUsers stripe_id
rails db:create db:migrate

We may also add a brand new validation to our Consumer, to verify the Stripe ID shall be all the time current. Add to your Consumer mannequin:

validates :stripe_id, presence: true, uniqueness: true

To create a reference of our Consumer on Stripe API, let’s add a callback to Consumer mannequin.

Add the code under to the Consumer mannequin.

...  before_validation :create_stripe_reference, on: :create  def create_stripe_reference
response = Stripe::Buyer.create(e mail: e mail)
self.stripe_id = response.id
finish
finish

Could be fairly fascinating to have a way to retrieve the stripe details about the client if we’d like it. Luckily, Stripe SDK supplies this methodology, which we are going to add to our Consumer mannequin too.

...  def retrieve_stripe_reference
Stripe::Buyer.retrieve(stripe_id)
finish
finish

Lastly, your Consumer mannequin ought to seem like this:

class Consumer < ApplicationRecord
has_secure_password
validates :e mail, uniqueness: case_sensitive: false
validates :stripe_id, presence: true, uniqueness: true
before_validation :create_stripe_reference, on: :create def create_stripe_reference
response = Stripe::Buyer.create(e mail: e mail)
self.stripe_id = response.id
finish
def retrieve_stripe_reference
Stripe::Buyer.retrieve(stripe_id)
finish
finish

Superior!! Let’s attempt our code on the console, run in your terminal:

rails c

Now you can create a Consumer, and the code will routinely contact Stripe API and create the reference.

Consumer.create(e mail: "person@check.com", password: "123456")

You’ll be able to take a look at the Stripe ID of this person with the instructions under.

person = Consumer.first
person.stripe_id

And to retrieve all of the Stripe data for this person, run:

person.retrieve_stripe_reference

That appears incredible.

The Plan mannequin shall be answerable for representing and dealing with enterprise guidelines for the subscription choices we are going to provide.

Run-on your terminal:

rails g mannequin Plan title description interval:integer price_cents:integer stripe_price_id
rails db:migrate

Take a more in-depth take a look at the Plan attributes:

  • Title shall be a string and represents the title of the plan;
  • Description shall be a string and represents brief textual content, describing what the plan gives;
  • Interval shall be an integer and represents the interval of charging the subscriber;
  • price_cents shall be an integer and represents the worth for the subscription, it must be cents as a result of Stripe works with cents values and it’s simpler to deal with the worth this manner.
  • stripe_price_id shall be a string and represents a reference to our Plan within the Stripe API.

That’s how the Plan mannequin will seem like:

class Plan < ApplicationRecord
validates :title,
:stripe_price_id,
:price_cents, presence: true
validates :title,
:stripe_price_id, uniqueness: true
enum interval: %i[month year] before_validation :create_stripe_reference, on: :create def create_stripe_reference
response = Stripe::Worth.create(
unit_amount: price_cents,
foreign money: 'usd',
recurring: interval: interval ,
product_data: title: title
)
self.stripe_price_id = response.id
finish
def retrieve_stripe_reference
Stripe::Worth.retrieve(stripe_price_id)
finish
finish

Take a more in-depth take a look at the Plan mannequin:

  • First, we outlined some validations, to verify title, stripe_price_id and price_cents shall be all the time current. We additionally outlined a validation to verify the title and the stripe_price_id shall be distinctive.
  • After that, we outlined our interval enum, rails will deal with these choices, so once we go the worth “month” for the interval, the framework will retailer 0 within the database and once we go the worth “12 months” it should retailer 1.
  • Then we outlined a callback to create a reference to our Plan on Stripe API.
  • The create_stripe_reference methodology shall be answerable for the all of the logic triggered on the callback.
  • The retrieve_stripe_reference will mainly return the Stripe reference of our Plan.

Let’s attempt our new mannequin on the console. Run in your terminal:

rails c

Now you can create a Plan, and the code will routinely contact Stripe API and create the reference:

# Month Subscription
Plan.create(
title: 'Month Subscription',
description: 'This subscription shall be charged each month',
interval: 'month',
price_cents: 500
)
# Yr Subscription
Plan.create(
title: 'Yr Subscription',
description: 'This subscription shall be charged yearly. Save $10 with this subscription.',
interval: '12 months',
price_cents: 5000
)

To retrieve all of the Stripe data for some plans, run:

# The 1 represents the ID of the file.
Plan.discover(1).retrieve_stripe_reference

The Stripe Price Docs.

The Subscription mannequin shall be answerable for representing and dealing with enterprise guidelines for a person’s subscription.

Run the next command in your terminal:

rails g mannequin Subscription plan:references person:references lively:boolean stripe_id
rails db:migrate

Taking a more in-depth look to the Subscription attributes:

  • plan shall be a reference to the plan that’s being bought;
  • person shall be a reference to the person that’s buying a plan;
  • lively shall be a boolean that represents if a subscription continues to be legitimate.
  • stripe_id shall be a string and represents a reference to the Subscription within the Stripe API.

Open the migration create_subscriptions and ensure to outline the default worth of the lively attribute:

...
t.boolean :lively, default: true
...

After that, let’s code the Subscription mannequin. That’s the way it ought to seem like:

class Subscription < ApplicationRecord
attr_accessor :card_number, :exp_month, :exp_year, :cvc
belongs_to :plan
belongs_to :person
validates :stripe_id, presence: true, uniqueness: true before_validation :create_stripe_reference, on: :create def create_stripe_reference
Stripe::Buyer.create_source(
person.stripe_id,
supply: generate_card_token
)
response = Stripe::Subscription.create(
buyer: person.stripe_id,
objects: [
price: plan.stripe_price_id
]
)
self.stripe_id = response.id
finish
def generate_card_token
Stripe::Token.create(
card:
quantity: card_number,
exp_month: exp_month,
exp_year: exp_year,
cvc: cvc

).id
finish
finish

Take a more in-depth take a look at the Subscription mannequin:

  • To begin with, we outlined some digital attributes. We is not going to retailer that knowledge, as a result of it’s delicate. So Stripe will deal with it for us.
  • After that, we outlined the relations of the mannequin, a belongs to Plan and Consumer.
  • The one attribute we are going to validate is stripe_id, it have to be current and be distinctive.
  • We even have a callback, that shall be triggered earlier than the validation of the file creation.
  • The create_stripe_reference shall be answerable for creating the reference of our subscription on the Stripe API. Notice that earlier than creating the subscription on Stripe API, we create a supply for the client, that would be the cost methodology.
  • The generate_card_token shall be answerable for passing the cardboard knowledge to Stripe API and return a token. Passing a token is safer than passing the cardboard knowledge, that’s why Stripe handles the cost supply this manner.

Let’s attempt our new mannequin on the console. Run in your terminal:

rails c

Now you can create a Subscription, and the code will routinely contact Stripe API and create the reference.

Subscription.create(
card_number: '5555555555554444',
exp_month: 06,
exp_year: 2029,
cvc: '123',
user_id: Consumer.first.id,
plan_id: Plan.first.id,
lively: true
)

Notice that Stripe has pre-defined allowed check card numbers. You’ll be able to test it out right here: Stripe Test Cards.

That’s superior!! Our Subscription is already working and you’ll see it on the Stripe Dashboard.

Stripe Dashboard

Typically we have to get monetary savings and a few subscriptions have to be canceled, let’s program the appliance to permit cancelations.

What we are going to do is mainly replace the file and the reference on Stripe API when lively is fake. Let’s code it.

Add a callback to cancel the subscription on Stripe API, with activeness conditional.

...before_update :cancel_stripe_subscription, if: :subscription_inactive?...

We additionally want so as to add the tactic that the callback name and the tactic that outline the situation.

...  def cancel_stripe_subscription
Stripe::Subscription.delete(stripe_id)
finish
def subscription_inactive?
!lively
finish
finish

To check if it really works, go to your rails console and run the instructions under:

Subscription.first.replace(lively: false)

Now the subscription is canceled, and you’ll verify it in your Stripe Dashboard.

Stripe Dashboard

For this submit, we could have controllers solely to indicate, create and replace subscriptions. As soon as the Plans CRUD is extra an administrative factor, I cannot create a controller for it now.

The Subscriptions Controller

To create the subscriptions controller, run the command under in your terminal:

rails g controller subscriptions present create replace

The command above will add some routes to our routes file, however we have to change it, as soon as we would like the routes contained in the namespace api/v1.

So your routes could seem like this:

Rails.utility.routes.draw do
namespace :api do
namespace :v1 do
submit '/signup', to: 'customers#signup'
submit '/signin', to: 'customers#signin'
get '/signedin', to: 'customers#signedin'
sources :subscriptions, solely: %i[show create update]
finish
finish
finish

After producing the controller, let’s write it. Since that’s a really generic rails controller, I cannot clarify the code of it on this article.

Your controller ought to seem like this:

module Api
module V1
class SubscriptionsController < ApplicationController
before_action :set_subscription, besides: %i[create]
def present
render json: @subscription
finish
def create
@subscription = Subscription.new(subscription_params)
if @subscription.save
render json: @subscription, standing: :created
else
render json: @subscription.errors, standing: :unprocessable_entity
finish
finish
def replace
if @subscription.replace(subscription_params)
render json: @subscription
else
render json: @subscription.errors, standing: :unprocessable_entity
finish
finish
personal def set_subscription
@subscription = Subscription.discover(params[:id])
finish
def subscription_params
params.require(:knowledge).allow(:card_number, :exp_month, :exp_year, :cvc, :user_id, :plan_id, :lively)
finish
finish
finish
finish

I’ll use Paw to run the requests and check the controller, however you’ll obtain the identical outcomes with any HTTP Consumer, like Postman or Insomnia.

Up your native server with the command under:

rails s

The Create Request

This request will set off a subscription creation.

Motion: POST

Endpoint:

http://localhost:3000/api/v1/subscriptions

Headers:

Content material-Sort: utility/json

Physique:


"knowledge":
"card_number": "5555555555554444",
"exp_month": "09",
"exp_year": "2029",
"cvc": "123",
"user_id": "1",
"plan_id": "1"

The response to this request ought to match the format under:

Create Response

The Replace Request

This request will cancel a subscription.

Motion: PUT or PATCH

Endpoint:

http://localhost:3000/api/v1/subscriptions/3

The quantity 3 on the endpoint above, represents the ID of the file we need to replace, it’s possible you’ll change it associated to the ID of your subscription.

Headers:

Content material-Sort: utility/json

Physique:


"knowledge":
"lively": false

The response of this request ought to match the format under:

Replace Response

The Present Request

This request will retrieve a subscription.

Motion: GET

Endpoint:

http://localhost:3000/api/v1/subscriptions/3

The quantity 3 on the endpoint above, represents the ID of the file we need to replace, it’s possible you’ll change it associated to the ID of your subscription.

The response of this request ought to match the format under:

Present Response

Stripe make the cost system integration be fairly easy and simple.

There are loads of sources on Stripe API that weren’t explored throughout this text. I imply to publish one other one sooner or later, associated to cost intent and webhooks for receiving the intent to replace the standing of a subscription.

You’ll be able to check the complete Stripe Docs here.

Need to Join?Connect on Twitter.

More Posts