Intermediate TDD in Rails : Encapsulating the Stripe Response


To encapsulate the parsing of the Stripe response in it's own class.


Step 1

I would like to make a call in the subscriptions_controller.rb create action like this:

Subscription.save_details(stripe_customer, current_user, plan_name) 

This should save the stripe_customer_token, plan_name, last 4 digits, expiration_month and expiration_month of credit card.

Step 2

In order to accomplish that, we need to navigate the stripe customer JSON response from the Stripe servers and retrieve the customer id and the credit card details. The Stripe API docs shows the structure of the customer object:

   "object": "customer",
   "created": 1426623031,
   "id": "cus_5tDSlyr30eqCTa",
   "livemode": false,
   "description": null,
   "email": null,
   "delinquent": false,
   "metadata": {
   "subscriptions": {
     "object": "list",
     "total_count": 0,
     "has_more": false,
     "url": "/v1/customers/cus_5tDSlyr30eqCTa/subscriptions",
     "data": [

   "discount": null,
   "account_balance": 0,
   "currency": "usd",
   "sources": {
     "object": "list",
     "total_count": 1,
     "has_more": false,
     "url": "/v1/customers/cus_5tDSlyr30eqCTa/sources",
     "data": [
         "id": "card_15hR1H2eZvKYlo2CpmgFpXLh",
         "object": "card",
         "last4": "4242",
         "brand": "Visa",
         "funding": "credit",
         "exp_month": 3,
         "exp_year": 2017,
         "fingerprint": "Xt5EWLLDS7FJjR1c",
         "country": "US",
         "name": null,
         "address_line1": null,
         "address_line2": null,
         "address_city": null,
         "address_state": null,
         "address_zip": null,
         "address_country": null,
         "cvc_check": null,
         "address_line1_check": null,
         "address_zip_check": null,
         "dynamic_last4": null,
         "metadata": {
         "customer": "cus_5tDSlyr30eqCTa"
   "default_source": "card_15hR1H2eZvKYlo2CpmgFpXLh"

Step 3

Copy the above JSON to spec/fixtures/customer.json.

Step 4

Let's write a stripe_customer_mapper_spec.rb that will encapsulate the navigation of the JSON document.

require 'rails_helper'

describe StripeCustomerMapper do

  it 'should map credit card expiration month' do
    h = JSON.parse("spec/fixtures/customer.json"))
    customer = Stripe::Customer.construct_from(h)    

    mapper =

    expect(mapper.credit_card_expiration_month).to eq(3)


Look at the fixture file, customer.json to find the credit card expiration date. It is 3, so we have 3 in the expect method. Run the test. It fails.

Step 5

Playing in the irb:

h = JSON.parse("spec/fixtures/customer.json"))
customer = Stripe::Customer.construct_from(h)   

We find that :[0].exp_month

will retrieve the expiration date of the credit card.

Step 6

Create the app/models/stripe_customer_mapper.rb and implement the method as follows:

class StripeCustomerMapper
  def initialize(customer)
    @customer = customer

  def credit_card_expiration_month[0].exp_month


Step 7

Here is the tests for expiration year and last 4 digits:

  it 'should map credit card expiration year' do
    h = JSON.parse("spec/fixtures/customer.json"))
    customer = Stripe::Customer.construct_from(h)    

    mapper =

    expect(mapper.credit_card_expiration_year).to eq(2017)

  it 'should map credit card last 4 digits' do
    h = JSON.parse("spec/fixtures/customer.json"))
    customer = Stripe::Customer.construct_from(h)    

    mapper =

    expect(mapper.credit_card_last4digits).to eq('4242')

Step 8

Here is the implementation that passes it. It is similar to our first test.

  def credit_card_expiration_year[0].exp_year

  def credit_card_last4digits[0].last4


In this lesson we encapsulated the logic to navigate the Stripe JSON response in StripeCustomerMaper class. This localizes the changes that may be needed in the future due to Stripe API changes to the mapper class.

Related Articles

Ace the Technical Interview

  • Easily find the gaps in your knowledge
  • Get customized lessons based on where you are
  • Take consistent action everyday
  • Builtin accountability to keep you on track
  • You will solve bigger problems over time
  • Get the job of your dreams

Take the 30 Day Coding Skills Challenge

Gain confidence to attend the interview

No spam ever. Unsubscribe anytime.