How To Build A Rails Backend Using Geocodio

This tutorial will show you how to build a Rails backend app that retrieves information about a user's Congressional District from the Geocodio API.

Geocodio is an amazing tool for any Rails developer looking to incorporate location-based data into their project. In this article, I’m going to break down how to integrate the Geocodio API into a website that will allow users to find and review the contact information for their Congressional Representatives.

Let’s get started!

Part One: Generating Our Application

First, we need to create and set-up our project. We can do that by running a simple rails generator in our terminal.

rails new code-sample-congress-search -–api

Note: You’ll want to include the name of your own application in place of code-sample-congress-search.

The --api tag included at the end of the generator will automatically format your application to emphasize the backend. It will cut out some inessential Middleware that pertains to frontend development in Rails and will also set your ApplicationController to inherit from Api instead of Base. If you want to build out frontend views in Rails itself, you may want to consider leaving this tag off.

Once the generator is finished its work, you’ll have a complete skeleton of a Rails API that you can use as your foundation. Go ahead and cd into your new directory.

cd code-sample-congress-search

Part Two: Configuring Our Gemfile

To work with Geocodio, we’re going to want to add a few important tools to our Gemfile. Open your Gemfile and insert the following:

gem 'geocodio' gem 'dotenv-rails' gem 'nokogiri', '>= 1.13.6'

You will also want to uncomment the already existing code from this block of commented text.

gem 'rack-cors'

Here’s a quick rundown on what these Ruby gems are going to do for us:

  • Geocodio: The most essential gem for our current purpose. The Geocodio gem will give us access to the open-source Geocodio Ruby library, which will make querying addresses in the API much more streamlined.
  • Dotenv-Rails: Will allow us to secure our API key in an environment file that won’t be exposed publicly, preventing possible security issues.
  • Nokogiri: I added the Nokogiri gem to fix a security error that was flagged by Github. You may not need to do this, but it might be a good idea to include it just in case. Use at your discretion.
  • Rack-CORS: Gives us the ability to permit an external source - or origin - to retrieve data from our resource. This is essential if you’re going to have a separate frontend application access data from our backend. More on this later.

To be certain everything has been installed correctly, you may want to run the following in your terminal:

bundle install

Part Three: Securing Our API Key

Now that we’ve installed Dotenv, let’s secure our API key for future use. We’ll need it when we’re ready to make a call to the Geocodio API.

Create a file in your root directory (in my case “code-sample-congress-search”) called .env. This is your environment file. Then, within that file, assign your API key from Geocodio - which you can access on your Dashboard - to a variable. That variable should be in ALL CAPS.

API_KEY=<Your API key goes here>

Next comes the most important part: you must add your new .env file to the .gitignore file, which should already be contained within your root directory. This ensures that your .env file does not get pushed to Github, exposing your API key publicly. This is crucial for the security of your application.

You’ll need to access your API_KEY eventually, but we’ll get to that soon.

Part Four: Building Resources

With that done, we’ll need to consider what resources we want to add to our application. In this particular case, since our functionality is limited to finding information about a Congressional District - and there aren’t any other dynamic relationships - we only need one resource: District. We will use the controller that this resource provides us to retrieve data from the Geocodio API.

rails generate resource District

By running this generator, we’ll construct a few important things:

  • A model called District.rb.
  • A controller called districts_controller.rb.
  • A collection of open routes in routes.rb.
  • A migration in our database to create a table called districts.

Note: Since we’ll only be using this controller to retrieve data from the Geocodio API, I did not include any attributes for our District resource. If you want to store data into an internal database, you will want to include necessary attributes when you generate your own resources.

To avoid any potential errors, let’s go ahead and migrate our database to get it out of our way.

rails db:migrate

Part Five: Adding Actions to Your Controllers

Okay, we’ve spent a lot of time generating and configuring, but now it’s finally time to start implementing our code!

Generally, when building out a Rails application, you would want to establish relationships between your models and add CRUD actions to your controllers that would allow you to Create, Read, Update or Delete instances of those models. But for our purposes, this backend application is fairly barebones. All we want is a single action within districts_controller.rb that can be used to call the Geocodio API and retrieve Congressional District data about an input address.

Before we do anything else, we need to make sure that we make our Dotenv and Geocodio gems available to our districts_controller by requiring them at the top of the file.

require 'dotenv-rails' require 'geocodio'

We should already have an empty DistrictsController class to work within. Let’s go ahead and use our Geocodio Ruby library to grab a sample address so that we can test if it’s working. I’ll explain the code once we’re done, but to follow along check out the Single Address section of the Geocodio API docs.

require 'dotenv-rails' require 'geocodio' class DistrictsController < ApplicationController def get_district geocodio = Geocodio::Client.new(ENV["API_KEY"]) location = geocodio.geocode(["1600 Pennsylvania Ave. Washington, DC 20500"], fields: %w[cd]).best district = location.congressional_districts render json: district end end

Let’s break everything down:

  1. First, I created a method named get_district, which I can call to activate this block of code.

  2. Next, I connected the application to the Geocodio library by creating an instance variable called geocodio and assigning it to Geocodio::Client.new(ENV["API_KEY"]). Notice that when I create a new instance, I pass in the API_KEY from my .env file. This will make sure that Geocodio recognizes me as a valid user, but without ever exposing the key to the public.

  3. With the library available to me, I run the .geocode() method on my geocodio instance. In square brackets, I pass in a string of an address that I want to look up. Usually you wouldn’t want to hardcode this, but I want to test to make sure everything is working before I abstract it into a variable. I chose the White House as an example address.

  4. I also pass in a fields parameter of %w[cd] into geocode() - which will append information about the address’ Congressional District onto the data that is returned from Geocodio. There are lots of different fields you can append to your results. Find them here.

  5. If we were to check what the location variable returns, we would get a response from Geocodio! It will include all of the requested information about the address we’ve provided.

  6. We could stop there, but I’d rather sift through only the essential data that we need. As such, I create one more variable, district, that is assigned to location.congressional_districts, which provides us all the data we need about the Congressional District of the address provided - without any extraneous information.

  7. Finally, I render the district variable as JSON, making the data easy to read and display on whatever frontend we choose.

Part Six: Setting Up Our Route

We have one more step to complete before we’ll actually be able to review and access the data we want to retrieve from the Geocodio API. We need to set up a route that will allow us to call the get_district action in our controller.

Navigate to your config directory and open the routes.rb file. This is where we build out our routes. Let’s go ahead and set up a GET route to call get_district.

get '/get_district' => 'districts#get_district'

Note: You may notice some code that is already in your routes file. When you generated the District resource, a group of routes named resources :districts was automatically built. This includes GET, POST, PATCH and DELETE routes for every District resource. I’ve chosen to delete this code, because we’re not going to need it right now - but you can make your own decision based on the needs of your application.

Part Seven: Testing Our Results

With our /get_district route wired up, we are all set to make our first test call to the Geocodio API. Let’s make sure everything is working as we would hope!

Go ahead and run a rails server in your terminal.

rails s

Then, in your browser, navigate to the /get_district route. Most likely, if you are using a Rails server, your server port will be 3000, so your URL should look like this:

http://localhost:3000/get_district

If you’ve followed the instructions to this point you should see a response from the Geocodio API that contains all of the requested data. We’ve made our first successful API call!

An Aside

Now that we’re officially making a successful request to the Geocodio API - and received a response - it’s time to chat a bit about integrating our backend with a frontend.

Ultimately, there are a lot of options here and I can’t cover them all. You could build your frontend within your already existing Rails application by incorporating views. You could also construct an entirely separate project using a language like JavaScript and an asynchronous technique like fetch() to grab the data from our Rails app.

In my case, I chose to use the React Javascript library - but from here on out I’ll try to keep things as all-purpose as possible. Just recognize that you may need to make some adjustments to your integration strategy depending on how you’ve elected to build your frontend.

Part Eight: Fetching Data from the Geocodio API

What we need to do to make our application a bit more useful - because not everyone is going to need to know the Congressional District data for a single, hard-coded address - is to find a way to abstract out our location variable. Regardless of your frontend strategy, we need to accomplish a few things to make this happen:

  1. We need to build a search form on our frontend that will allow us to capture an address from a user as a string.
  2. When the user submits their address string, we need a means to send that data from our frontend to our backend Rails API - specifically into our get_district method in DistrictsController.
  3. We need to pass the address string data into the .geocode() method, which will then allow us to render the data for that new address as JSON.

In my React frontend, I constructed a Search component that renders a search bar and captures the value entered into that form on submit.

When the page re-renders after the submit, I make a fetch() call to the Rails backend. Here’s what that fetch looks like for reference:

const fetchDistrict = () => { fetch(`http://localhost:3000/get_district?search=${address}`), method: “GET”, headers: { “Content-Type”: “application/json” } }) .then(resp => resp.json()) .then(data => { if (data.error){ console.log(“Something went wrong”) } else { setDistrict(data) } }) }

Since this isn’t a React tutorial, the main thing to focus on here is the first line of my fetch. When I call the get_district route, I query a search parameter and pass in the address state, which includes the address string submitted in my search bar. By including this in the URL that I’m fetching, I am effectively sending the address string to my backend server as a parameter.

Once I’ve added one small change to my districts_controller, this will return the Congressional District data for any address I enter into the form.

What do I need to add?

require 'dotenv-rails' require 'geocodio' class DistrictsController < ApplicationController def get_district addressString = params[:search] geocodio = Geocodio::Client.new(ENV["API_KEY"]) location = geocodio.geocode([addressString], fields: %w[cd]).best district = location.congressional_districts render json: district end end

Since the fetch creates a parameter called search, which contains our address string - we can return that string through params[:search] in our districts_controller.

I’ve assigned params[:search] to a variable called addressString. When I pass addressString into the square brackets in the .geocode() method, Geocodio will retrieve information for the submitted addresses. The rest of our code will render the requested district information as JSON and send a response back to the frontend for the data to be displayed!

This is awesome. We can enter an address into the search bar on our frontend, retrieve the Congressional District information about that address from the Geocodio API through our backend and then render the retrieved data for the user to consume. This is exactly what we want.

But there’s still one more thing to consider…

Part Nine: Rack-CORS

If we want to utilize our Rails backend in unison with a separate frontend - in my case React - then the frontend will need permission to receive the incoming data.

Earlier, we uncommented the ‘rack-cors’ gem, but we haven’t actually done anything with it yet. Rack CORS allows us to permit an external source - or origin - to retrieve data from our Rails backend. It’s a security feature that is totally customizable. You decide what origins can access data from your app. If an unknown origin makes a request, they won’t receive a response.

To configure our Rack CORS, navigate into the config/initializers directory and find the file called cors.rb.

Inside the file, uncomment the following code.

Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins '*' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end

Notice that origins is currently set to an asterisk(*). This is where we set which domains have permission to access our Rails backend. In this case, the asterisk indicates that any domain that were to attempt to retrieve data would receive a response. That’s okay for now, but if our site went live, it could cause some real security issues.

Since my React server currently runs on localhost:3001, I’m going to pass that into origins so that it is the only domain that can access data from the backend.

origins 'http://localhost:3001'

Now, when my React frontend makes a call to my Rails backend, it will receive the data from the Geocodio API - but no other applications will be able to do the same.

Conclusion

That’s it! We now have a working application that will allow a user to search for their address and retrieve information about their Congressional District from the Geocodio API. This is just one of many ways to integrate Geocodio with a Ruby On Rails application.

For a closer look - or to follow along, check out the sample code for Congress Search - which was built with a Ruby On Rails backend and a React frontend.

Don't have an account? Sign up to get 2,500 free lookups a day.

Create an API Key

API Documentation

See how to integrate geocoding, Census data, and more
Go to Docs

Metabase

Metabase is an easy, open source way for everyone in your organization to ask questions and learn from data.

Create an API Key

Create a free Geocodio API key
Copyright © 2014-2022 Dotsquare LLC, Norfolk, Virginia. All rights reserved.