DEV Community

nico_lrx
nico_lrx

Posted on

How to Use Stripe Checkout From a Rails Controller (Without Javascript)

As I was launching my first French online course, I needed to use Stripe to process payments. The course was built using Ruby on Rails as it's the technology I am most proficient with.

However, I felt it was hard to create a simple experience for the end-user:

  • The user visits the Devise Registration page to create an account
  • When he/she clicks on the button to submit the form, he/she is redirected to Stripe Checkout to perform the payment

If you follow Stripe's logic, an event listener in Javascript will listen to the submission of the form, perform an Ajax call to create the Stripe session, and then redirect to Checkout.

However, this will prevent the normal submission of Devise's registration form. You will have to submit the Devise form using Ajax, which is not the easiest.

Here are a few steps to implement a simpler solution, using no Javascript. The whole Stripe logic is managed in a Rails controller.

Move Stripe's logic to Devise's Registration controller

After setting up Devise, you will have to generate Devise's controllers to be able to customize them. Just run the following command in your terminal:

rails generate devise:controllers users

Then, change the controllers to the devise_for routes:

devise_for :users, controllers: { registrations: 'users/registrations' }
Enter fullscreen mode Exit fullscreen mode

Now we are all set to customize the after_sign_up_path_for method of the Registration controller.

  • First, we initialize the Stripe API Key.

  • Then, we create a session with our product's parameters.

  • Finally, we return the session URL. This will make the page to be automatically redirected to the Checkout generated URL.

def after_sign_up_path_for(resource)
    super(resource)

        Stripe.api_key = "#{ENV['STRIPE_API_KEY']}"

        # See https://stripe.com/docs/api/checkout/sessions/create
        # for additional parameters to pass.
        # {CHECKOUT_SESSION_ID} is a string literal; do not change it!
        # the actual Session ID is returned in the query parameter when your customer
        # is redirected to the success page.
        session = Stripe::Checkout::Session.create(
            success_url: "success_url",
            cancel_url: "cancel_url",
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: [{
                # For metered billing, do not pass quantity
                quantity: 1,
                price: ENV['STRIPE_PRICE_ID']
            }],
            locale: "fr",
            customer_email: current_user.email
        )

        return session.url

  end
Enter fullscreen mode Exit fullscreen mode

Listen to Stripe's webhook

After setting up the logic to redirect the user to Checkout, we need to listen to Stripe's events to make sure he/she completed the payment of the product.

Stripe has a comprehensive documentation about setting up webhooks so I won't enter into details here.

In our routes, we add the following line (assuming you have created a Stripe controller):

post 'webhook', to: "stripe#webhook"
Enter fullscreen mode Exit fullscreen mode

In order to make it work, you need to initialize Stripe's API key. Add the following method to your Stripe controller, with a before action so it's called before the webhook method:

before_action :set_stripe_api, only: [:webhook]

...

  private 

  def set_stripe_api
    Stripe.api_key = "#{ENV['STRIPE_API_KEY']}"
  end
Enter fullscreen mode Exit fullscreen mode

Then, we add the webhook method to the Stripe controller. We use here a case / when loop to process the events we are listening to (don't forget to register them in Stripe's webhook dashboard):

    def webhook
        payload = request.body.read
        event = nil

        begin
            event = Stripe::Event.construct_from(
                JSON.parse(payload, symbolize_names: true)
            )
        rescue JSON::ParserError => e
            # Invalid payload
            respond_to do |format|
                format.json { render json: { error: e }, :status => :bad_request } 
            end
        rescue Stripe::SignatureVerificationError => e
            # Invalid signature
            respond_to do |format|
                format.json { render json: { error: e }, :status => :bad_request } 
            end
        end

        data_object = event.data.object

        case event.type
        when 'charge.succeeded'
            # get the data (see doc)
            customer_id = data_object["customer"]
            email = data_object["billing_details"]["email"]
            # do something with the customer_id and email
            # ...
        else
            puts "Unhandled event type: #{event.type}"
        end

        respond_to do |format|
            format.json { render json: {}, :status => 200 } 
        end
    end
Enter fullscreen mode Exit fullscreen mode

Voilà ! You have a working Stripe Checkout implementation without using any Javascript. When the user will submit the Devise registration form, he/she will be redirected automatically to Stripe Checkout!

Oldest comments (1)

Collapse
 
myriamsaenz profile image
Info Comment hidden by post author - thread only accessible via permalink
MyriamSaenz

our prebuilt UI components, to create a payment form that lets you securely collect a customer's card details without handling . جلب الحبيب بالصورة

Some comments have been hidden by the post's author - find out more