Rails Routing - resources vs. resource Methods

timtran007

Tim Tran

Posted on January 8, 2023

Rails Routing - resources vs. resource Methods

As I am learning more and more about Ruby and Rails, I am beginning unfold CRUD actions and their related behavior in /config/routes.rb file.

What I have gathered so far is that Rails makes it easy to create routes. You can do it by hand (saved for custom non RESTful routes) or automatically with the resource method (or shall I say resources method... more on this later).

However, attention to detail is key as I was stuck on trying to pass an rspec test by automatically creating my 6 RESTful routes.

The Setup

Let's go ahead and set up a new Rails API application (you have Rails installed already)

rails new bird-api --api --minimal

This will create a new Rails API application for us to work through.

Then let's go ahead and create our migration and model through the use of Rails generator:

rails g model Birds name species

This will create our migration of a birds table with columns of name and species in string format.

Then we can go ahead and migrate with:
rails db:migrate

Great!!

Let's go ahead and finish up by generating a controller to handle our routes.

rails g controller birds

Creating Routes By Hand

Let's go ahead and dive into our routes.rb file and create the routes that we want for our birds controller to provide a JSON rendered response.

Rails.application.routes.draw do
  #let's handle our routes manually below
  get 'birds', to: 'birds#index'
  get 'birds/:id', to: 'birds#show'
end
Enter fullscreen mode Exit fullscreen mode

We can do a quick check to see if this works with:
rails routes

Creating the Controller Actions

Now let's quickly set up our controller actions to handle our RESTful routes of index and show.

class BirdsController < ApplicationController
  #let's go ahead and add our controller actions
  def index
    render json: Bird.all, status: :ok
  end

  def show
    bird = Bird.find(params[:id])
    if bird
      render json: bird, status: :ok
    else
      render json: {error: "bird not found"}, status: 
      :not_found
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Great! We can check to see if this works by adding seed data and seeding our application.

Then we can spin up our server:

rails s

For our RESTful route for /birds, we should see something similar (dependent upon seed data):

Image description

And for our RESTful route for /birds/:id, we should see:

Image description

Let's Automate Our RESTful Routes With resource

Great! Now let's refactor our code to automate the Routes.

We can do this by going into our config directory and routes.rb file

Rails.application.routes.draw do
  #manual way to create our route
    #get 'birds', to: 'birds#index'
    #get 'birds/:id', to: 'birds#show'
  #automated way to create our routes
    resource :birds, only: [:index, :show]
end
Enter fullscreen mode Exit fullscreen mode

Let's go ahead and check our routes to make sure that we got our two routes by running:
rails routes

Oh no!! We only have one route for our birds controller with the action of show...

Image description

Why do we only have one route created?

'resource' Method vs. 'resources' Method

Like I mentioned before... attention to detail is the key here. By not adding an 's' to the end of 'resource' method we only generate the show action for the birds controller in the code above.

Let's take a deeper look into the RESTful routes created if we run just resource :birds instead of the additional `only: [:index, :show]...

We get only 5 RESTful routes that do not make sense at all:

Image description

As you can see there are actions for our birds controller for updating and destroying all birds... With RESTful routes conventions, we must target a specific bird to update and destroy.

Now let's go ahead and take a look at if we used the 'resources' method instead:


Rails.application.routes.draw do
resources :birds
end

We get 6 RESTful Routes that actually makes sense! Two for our /birds and four for individual birds /bird:

Image description

Conclusion

We can solve the problem of creating our birds controller action of index and show by simply writing:

resources :birds, only: [:index, :show]

Rails provides easy ways to automate tedious tasks such as creating routes, but it can get tricky at times troubleshooting since you don't necessarily get an outright error that says don't use 'resource', instead use 'resources'.

The devil is in the details, as I struggled to pass my rspec tests all because I left out the 's' in resources. I hope you can learn from my experience of troubleshooting the automation of creating RESTful routes.

TLDR;

Use resources :controllers_name and not resource :controllers_name when automating the creation of RESTful routes.

💖 💪 🙅 🚩
timtran007
Tim Tran

Posted on January 8, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related