How to Use Stripe Checkout From a Rails Controller (Without Javascript)
Tags: rails, stripe, checkout
Published: 2021-11-23 14:25:41

---
title: How to Use Stripe Checkout From a Rails Controller (Without Javascript)
published: true
description: Here is a tutorial to use Stripe Checkout with Ruby on Rails without even writing a single line of Javascript.
tags: rails,stripe,checkout
//cover_image: https://direct_url_to_image.jpg
---

As I was launching my [first French online course](https://formation.lalanguefrancaise.com), 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](https://github.com/heartcombo/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' }
```

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
```


## 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](https://stripe.com/docs/webhooks) 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"
```

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
```

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
```

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!