FullStack Labs

Please Upgrade Your Browser.

Unfortunately, Internet Explorer is an outdated browser and we do not currently support it. To have the best browsing experience, please upgrade to Microsoft Edge, Google Chrome or Safari.
Upgrade

REST-ing with Active Resource

Wrap a restful API using Rails and Active Resource

Written by 
Hernan Orozco
,
Senior Software Engineer
REST-ing with Active Resource
blog post background
A Day in The Life of a Software Engineer at FullStack Labs
2020 Software Development Price Guide & Hourly Rate Comparison
How Company Culture Attracts Top IT Talent in Colombia

In this tutorial, we will create a simple Ruby on Rails application that will connect to a local RESTful service using Active Resource.

Note: I will be using Ruby 2.6.5p114 and Rails 6.0.2.2

Overview

Active Resource is a wrapper for REST web services made in Ruby that can be used in Ruby on Rails. It allows you to map external resources to ActiveRecord-like Ruby objects. It needs a class/model to represent the resource and a site value that will contain the URI for the resource.

-- CODE language-ruby keep-markup --
class Post < ActiveResource::Base
self.site = "https://api.uri.com"
end

(ActiveResource model definition)

As you can see, the Post model inherits from ActiveResource::Base and a site var was defined with an URI pointing to the external API.

-- CODE language-ruby keep-markup --
p = Post.find 1
p.title = "New Title"
p.save

(ActiveResource Usage: find and update)

When you call the first line, Active Resource will perform a GET request to the site url to ask for the resource for the id 1 (https://api.uri.com/posts/1.json). The post object will have the keys returned in the API response as properties of the model. This instance also includes setter methods to change the properties. When the `save` method is called, a PUT request will be sent to update the resource in the API.

Let's create a simple REST server!

Now that we know what Active Resource is we can set it up in our Rails application. However, we will need a RESTful service to demonstrate Active Resource.

Note: We can connect to any service (even the ones that are not RESTful), however, Active Resource will work best if the service meets the REST principles.

We’re going to use the JSON Server library to create a simple local service. Install the library globally in your system by running: 

-- CODE language-ruby keep-markup --
npm install -g json-server

I created a dataset for this tutorial to give our JSON server some seed data, which you can find on this Github Repo

To start the server, run this command in the same path you have the db.json file:

-- CODE language-ruby keep-markup --
json-server --watch db.json

A local REST server will be running on port 3000 and serving the data from the db.json.

Time to create our Rails app

Ok, now that we have a REST server running on port 3000, it’s time to create our Rails app. Run the following commands:

	
rails new resting -d postgresql -T --skip-turbolinks # create app
cd resting 
bundle install # install gems
bundle exec rails db:create # create database
	

Active Resource should be added as a gem, so add this line to the Gemfile

-- CODE language-ruby keep-markup --
gem 'activeresource

Then run bundle install again:

-- CODE language-ruby keep-markup --
bundle install

Ok, now that we have the gem installed, let’s scaffold a User resource.

-- CODE language-ruby keep-markup --
bundle exec rails g scaffold User name:string username:string email:string phone:string website:string

This will create a model, a controller, and views for users. Since we’re not planning to use ActiveRecord or our database for this app and we’re going to get the resource from our REST server, we should remove the auto-generated migration. Go to db/migrate and remove the #_create_users.rb file.


Next, let’s add the users index action as root. Go to config/routes.rb and add this line:

-- CODE language-ruby keep-markup --
root to: 'user#index'

Now, run the Rails server on a port other than 3000, since our REST server is using port 3000. Let’s choose 3001.

-- CODE language-ruby keep-markup --
bundle exec rails s -p 3001

If you try to visit localhost:3001, you should get an error. This is because our User model is still inheriting from ActiveRecord and there is no users table. To use the user list from our REST server, change the User model to inherit from ActiveResource instead of ActiveRecord.

The user model that inherits from ApplicationRecord should now inherit from ActiveResource::Base. Additionally, we need to set up the public API url by adding a class variable called site that should match with our local service url. We also need to set the include_format_in_path config as false. This will avoid the .json at the end of all the requests. The user class should look like this:

-- CODE language-ruby keep-markup --
class User < ActiveResource::Base
self.site = "http://localhost:3000"
self.include_format_in_path = false
end

Now, reload the page and you should get a view like this:

This list is loaded from our local REST server in port 3000. Pretty cool, huh? We don't need to add extra code to get the list directly from the server because ActiveResource is doing that for us. 

Let’s add the gem, httplog, to the gemfile and run bundle install. This will allow us to log all HTTP requests performed in our app directly to the Rails log:

-- CODE language-ruby keep-markup --
# Gemfile
gem ‘httplog’

# Terminal
bundle install

The scaffold generates an action in the index controller that calls the all method from the User class (User.all), which is a method from ActiveResource. Behind the scenes, it performs a GET request to our base site url using our name in plural, so the request is similar to this: GET http://localhost:3000/users

Note: By default, the resource name is the class name in plural. If your endpoint does not match the plural form of the model name, you can override it by calling the self.element_name method like this: self.element_name = "other_user_resource_name" inside the class.

If we continue interacting with the page, we’ll notice that the show action works as well. It will perform a get request with the user id: GET http://localhost:3000/users/1

The destroy action will work, so you can test removing a user. Activeresource will perform a DELETE request to our REST server and the response will be an empty object `{}`

Now, let’s check the create action. Go to http://localhost:3001/users/new in the user index view and fill out the form. In the console, you will see something like this:

You can see that the form params were passed as a POST body to the REST server. Magic!

However, the update action is not going to work like the others. This is because Active Resource instances do not implement the “update” method, so we need to modify the update action in the user’s controller like this:

	
def update
    respond_to do |format|
      @user.attributes = user_params.merge({id: params[:id]})
      if @user.save
        format.html { redirect_to @user, notice: 'User was successfully updated.' }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end
	

As you can see, we changed the “update” call for a “save” call, and we also set the user attributes in a line before that call. It’s important to include the resource id in the params, so Active Resource knows what’s going to be updated.

Add a relationship

Now that we have a single resource, let’s create a relationship for it. The resource name will be “Album.” Users can have many Albums, so add a link to the user show view to display all their Albums. Additionally, in that view, we should also be allowed to remove Albums. 

Create an Album model that inherits from Active Resource. This model should also contain the same configuration as the user model.

-- CODE language-ruby keep-markup --
class Album < ActiveResource::Base
self.site = "http://localhost:3000"
self.include_format_in_path = false
end

Now, let’s add the relationship in the User model.

-- CODE language-ruby keep-markup --
has_many :albums

Next, go to config/routes.rb and modify the user resource clause to match this:

-- CODE language-ruby keep-markup --
resources :users do
resources :albums, only: [:index, :destroy]
end

As you can see, I’m adding an index and destroy action inside the user resources. So we need to create an albums_controller.rb file in controllers and create the actions:

	
class AlbumsController < ApplicationController
  before_action :set_user, only: [:index, :destroy]
  before_action :set_album, only: [:destroy]

  def index
    @albums = @user.albums
  end

  def destroy
    @album.destroy
    respond_to do |format|
      format.html { redirect_to user_albums_path(@user), notice: 'Album was successfully destroyed.' }
    end
  end

  private

  def set_album
    @album = Album.find(params[:id])
  end

  def set_user
    @user = User.find(params[:user_id])
  end
end
	

Now we need a view for the index action. First, we should add the link to the index action in the user show file, so add this to app/views/users/show.html.erb

-- CODE language-jsx keep-markup --
<%= link_to 'Albums', user_albums_path(@user) %> |

Next, we should create an albums folder inside the views along with an index file. The file will be in this path: app/views/albums/index.html.erb and should contain this:

-- CODE language-jsx keep-markup --
<p id="notice"><%= notice="" %=""></%=></p>

<h1>Albums for <%= @user.name="" %=""></%=></h1>

<table></table>

 <thead></thead>
   <tr></tr>
     <th>No.</th>

     <th>Title</th>

     <th>User</th>

     <th colspan="1"></th>

   

 

<tbody></tbody>

   <% @albums.each_with_index="" do="" |album,="" index|="" %=""></%>

     <tr></tr>

       <td><%= 1="" index="" +="" %=""></%=></td>

       <td><%= album.title="" %=""></%=></td>

       <td><%= @user.name="" %=""></%=></td>

       <td><%= link_to="" 'destroy',="" user_album_path(@user,="" album),="" method:="" :delete,="" data:="" {="" confirm:="" 'are="" you="" sure?'="" }="" %=""></%=></td>

     

   <% end="" %=""></%>

 




<br>

<%= link_to="" 'back',="" user_path(@user)="" %=""></%=>

Ok, that should do it. You can now navigate to the user Albums list, see the Albums that belong to each user, and remove an Album

In the controller, when we set the Albums @albums = @user.albums, Active Resource is performing this call: http://localhost:3000/albums?user_id=1

Conclusion

This is just a small demonstration showing some of the capabilities of Active Resource. It supports many more features and customizations, such as:

  • Custom JSON formats – we can define the way the active resource is going to map the resource
  • Add default headers to the requests
  • Error handling and validations
  • Timeouts
  • And many more...

I invite you to go to the official documentation and see all the things you can do with this amazing tool.

Note: this isn’t always the right tool for the job; it depends not only on the use case but also how the REST service was created. Sometimes it’s more complicated to configure Active Resource than build a custom wrapper, so only use this if it fits your use case. At FullStack Labs, we have Ruby on Rails developers ready to build any custom software you might need.

Check out the Github Repo for this tutorial to see the completed app.

Hernan Orozco
Written by
Hernan Orozco
Hernan Orozco

I've always loved the idea of an algorithm, that a computer can follow a series of steps to solve a problem. For me, coding is just plain fun, and the more I learn, the more I enjoy it. It's not just for my own gratification — each piece of software I build improves lives. I've built software for the largest bank in Colombia, a major health insurer, and an exoskeleton manufacturer. When I develop, I know that I'm part of something larger than just myself. I'm analytical, reliable, and committed. In addition to programming, I love photography and making music.

FullStack Labs Icon

Let's Talk!

We’d love to learn more about your project. Contact us below for a free consultation with our CEO.
Projects start at $50,000.

company name
name
email
phone
Type of project
Reason for contact
How did you hear about us?
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.