DEV Community

Cover image for Rails webhook integration development with Ngrok
Dídac
Dídac

Posted on

Rails webhook integration development with Ngrok

All begin when I started using Mollie, it's a PSP (Payment Service Provider) like Stripe and it has a ruby wrapper, but if you want to test payments in a development environment (localhost) you need a valid URL so they can reach you via webhook (if you want to validate the payment, the webhook URL parameter is mandatory).

The solution was easy I just create an ngrok tunnel and I change the default_url_options with an environment variable depending if I was working on something that needed only my local machine or other services.

For running my app with mollie webhooks i needed to do this:

  • Start ngrok
  • Change ENV variables for the new ngrok https url
  • Start my app
  • Start Sidekiq (for background jobs)

IMO it's not to much but at some point becomes annoying so I decided to make it easier for me, now i only have:

  • Start my app
  • Start Sidekiq

Here it is how to did it:

  • Install ngrok v2+ in your computer
  • Add ngrok-tunnel in your Gemfile
group :development do
  gem 'ngrok-tunnel'
  # Cool stuff for later but not really needed
  gem 'tty-box'
end
  • In puma.rb we add this code at the bottom
if ENV["IS_DEV_ENV"]
  begin
    options = {
      # App port
      addr: ENV.fetch("PORT") { 3000 },
      # ngrok system files
      config: File.join(ENV["HOME"], ".ngrok2", "ngrok.yml"),
    }

    # In case that you have a pay plan you can create
    # tunnels with custom subdomains
    options[:subdomain] = ENV["NGROK_SUBDOMAIN"] if ENV["NGROK_SUBDOMAIN"]

    # Region (since I only work in the EU is hardcoded)
    options[:region] = "eu"

    # Create tunnel
    Ngrok::Tunnel.start(options)

    # Create cool box
    box = TTY::Box.frame(width: 50, height: 10, padding: 2, title: {top_left: "<NGROK>", bottom_right: "</NGROK>"}, style: {fg: :green, bg: :black, border: {fg: :green, bg: :black}}) do
      "STATUS: #{Ngrok::Tunnel.status}\nPORT:   #{Ngrok::Tunnel.port}\nHTTP:   #{Ngrok::Tunnel.ngrok_url}\nHTTPS:  #{Ngrok::Tunnel.ngrok_url_https}\n"
    end
  rescue => error
    box = TTY::Box.frame(width: 50, height: 5, align: :center, padding: 1, title: {top_left: "<NGROK>", bottom_right: "</NGROK>"}, style: {fg: :red, bg: :black, border: {fg: :red, bg: :black}}) do
      "I couldn't create the tunnel ;("
    end
  end
  puts "\n#{box}\n"
end

Let's comment this code:

  • ENV["IS_DEV_ENV"] : Since Rails.env.development? is not loaded (at least in Heroku) in this point of the app we are using an environment variable that is only set in your secrets.yml or application.yml only in the development section and it needs to be set to true.
    development:
        IS_DEV_ENV: "true"
  • In the options hash we have the app port and the home directory where the ngrok files are located.
  • options[:subdomain] In case that you are an ngrok subscriber you can have a custom subdomain so I left the code here just in case I became a subscriber one day.
  • options[:region] This is not in an ENV variable because we are based in the EU and we don't work outside of it, so I just hardcoded EU but you can choose between:
    • us - United States (Ohio)
    • eu - Europe (Frankfurt)
    • ap - Asia/Pacific (Singapore)
    • au - Australia (Sydney)
  • WHAT'S IN THE box ????!!! just to make it cooler (at least for me) it's showing a nice box with the ngrok information.

  • In case ngrok cannot be connected we use the box to show that we cannot connect

Change the varibles

You maybe don't need this if you just want to test Mollie payments but for me was nice to have.

To change the config dynamically I choose a way that I think it's far from okey but it works (yeah i know it's running on every request). In the application_controller.rb I added this method:

before_action :set_ngrok_urls, if: "Rails.env.development?"

def set_ngrok_urls
    if Ngrok::Tunnel.running?
      # Getting current url
      url = Ngrok::Tunnel.ngrok_url_https

      # Variable hash
      default_url_options = {host: url}

      # Overwriting current variables
      Rails.application.config.action_controller.asset_host = url
      Rails.application.config.action_mailer.asset_host = url
      Rails.application.routes.default_url_options = default_url_options
      Rails.application.config.action_mailer.default_url_options = default_url_options
    end
  end

So what I'm doing here is in case that the environment is development I'm executing the function set_ngrok_urls and checks if ngrok is connected.

Then I get the current ngrok https URL and I create a hash (this hash is needed for the routes and the mailer default URL's) the two first only use the url.

That will be all, hope this works for some people and please if I did something very wrong leave a comment.

Bibliography

Top comments (1)

Collapse
 
jackwetson profile image
JackWetson

Great article! As a free ngrok user we added the default URL options to the bottom of our puma.rb rather than in application.rb and it works great.

We also updated some of our other systems, such as mailgun inbound routes in the same space