LaunchSchool - An Online School for Developers /

Blog

Process Payments With Paypal in Rails, Part 1 - Basic Checkout

This is the first article in the “Process Payments with Paypal in Rails” tutorial series:

Integrating Paypal to your Rails application is quite simple. In this tutorial, we will walk you through a basic checkout process to have Paypal process payments and notify our Rails app after payment is made.

As an example we will have an imaginary “Cookery School” application to sell online cooking courses. You can check it out here:

1
2
3
4
5
6
git clone https://github.com/gotealeaf/paypal-basics
cd paypal-basics
rake db:create
rake db:migrate
rake db:seed
rails s

Step 1. Creating your Paypal Developer account

You should sign up in Paypal Developer site and create merchant and buyer accounts in the Sandbox/Accounts/Dashboard:

You can create yours at your account. Those will be valid while you are logged in at Paypal Developer site. I have created two accounts:

Step 2. Redirecting to Paypal url

At ‘registrations_controller.rb’ we will redirect to Paypal URL after the registration is successfully saved:

1
2
3
4
5
6
7
8
9
  # POST /registrations
  def create
    @registration = Registration.new(registration_params)
    if @registration.save
      redirect_to @registration.paypal_url(registration_path(@registration))
    else
      render :new
    end
  end

This URL is produced by registration and course params. Next method is added to our ‘registration.rb’ model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  def paypal_url(return_path)
    values = {
        business: "merchant@gotealeaf.com",
        cmd: "_xclick",
        upload: 1,
        return: "#{Rails.application.secrets.app_host}#{return_path}",
        invoice: id,
        amount: course.price,
        item_name: course.name,
        item_number: course.id,
        quantity: '1'
    }
    "#{Rails.application.secrets.paypal_host}/cgi-bin/webscr?" + values.to_query
  end

You can manage your applications parameter from ‘config/secrets.yml’ file. We will add Paypal URLs and our local URLs for both environments development and production at ‘config/secrets.yml’ file:

1
2
3
4
5
6
development:
  paypal_host: https://www.sandbox.paypal.com
  app_host: http://our_ngrok_url
production:
  paypal_host: https://www.paypal.com
  app_host: https://launchschool.com/

After that we can sell, filling registration data at our desired course, and clicking “Registration Payment”:

We can see how we are redirected to Paypal standard form, with our course details and price. All prepared just to be purchased.

Step 3. Creating a web hook to manage payment notifications

At this point we can receive payments at our merchant account. But do we know if those payments are really done? No, right now our application does not know if a registration was paid or not. For that purpose we need to create a webservice where Paypal can connect to notify when the payment is done.

In ‘config/routes.rb’ create the routes:

1
2
  post "/registrations/:id" => "registrations#show"
  post "/hook" => "regstrations#hook"

First for ‘return_url’ (show invoice), and second for the ‘notification_url’ service.

The controller should answer these requests. Add to your ‘registrations_controller.rb’:

1
2
3
4
5
6
7
8
9
10
  protect_from_forgery except: [:hook]
  def hook
    params.permit! # Permit all Paypal input params
    status = params[:payment_status]
    if status == "Completed"
      @registration = Registration.find params[:invoice]
      @registration.update_attributes notification_params: params, status: status, transaction_id: params[:txn_id], purchased_at: Time.now
    end
    render nothing: true
  end

Removing protect_from_forgery process in order to turn off csrf checking when Paypal send a plain HTTP POST.

Here we need to add some attributes to our Regstration model, in order to catch notifications details. So that we will create a migration:

1
rails g migration add_params_status_transaction_id_purchased_at_to_registrations notification_params:text status:string transaction_id:string purchased_at:datetime

Now we need to inform to Paypal where to transfer the notification. Then we need to add notify_url parameter to our paypal_url creation, in ‘registration.rb’ model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  serialize :notification_params, Hash
  def paypal_url(return_path)
    values = {
        business: "merchant@gotealeaf.com",
        cmd: "_xclick",
        upload: 1,
        return: "#{Rails.application.secrets.app_host}#{return_path}",
        invoice: id,
        amount: course.price,
        item_name: course.name,
        item_number: course.id,
        quantity: '1',
        notify_url: "#{Rails.application.secrets.app_host}/hook"
    }
    "#{Rails.application.secrets.paypal_host}/cgi-bin/webscr?" + values.to_query
  end

Step 4. Testing

Now is the moment to start your app (remember, 3000 is the default port): rails s

Expose your service to be accessed by Paypal

If we think a while we can realize that notification_url and return_url can not be accessed from Paypal because they are not exposed in the public internet, they are in our localhost.

We will use the Ngrok Service for tunnelling our local application to a Ngrok subdomain. So we will be able to allow Paypal to send a HTTP POST to our localhost and test our payment process locally.

First install Ngrok downloading it for your system. Or just run your package manager if you are on Linux:

1
sudo apt-get install ngrok-client

Now you can publish your application just running the command: ngrok 3000, since the rails port is 3000.

It will respond with a URL, http://3c99b47d.ngrok.com in my case. This is the app_host you should configure in your ‘config/secrets.yml’ file. Replace app_host: http://our_ngrok_url by app_host: http://3c99b47d.ngrok.com.

Testing from Paypal Developer site

Now you should access your ngrok URL, select a course and fill in your registration details:

Clicking registration button you will be redirected to Paypal checkout form (paypal_url), with all course details and price:

Login with your buyer paypal account, and you will be redirected to payment confirmation page:

After you confirm the payment, you will see the success page:

Here you can click the return link (“Return to SandboxTest Account’s Test Store”) to return to our Academy page. Then you will be redirected to your invoice page:

Here you can see notification time, status and identifier. You can also login with your buyer or merchant accounts in Sandbox Paypal site where you can see payments received:

Conclusions

This is a basic solution to process payment with Paypal. The advantages are:

  • Pretty easy and quick way to implement a payments gateway on your site
  • No need to store credit card numbers locally and no need to worry about PCI Compliance
  • You get notified by Paypal when payments are processed.

The disadvantage is that you have to send your customers away from your website to go to Paypal to finish their payment process, which can be disruptive for the user experience.

For further information you can visit the following links: