DEV Community

Justin Saborouh
Justin Saborouh

Posted on

Rails Restful Routing

When building an interactive full-stack website, there are going to be cases where the user communicates with the server, and the server has to respond with or update the corresponding data. In the simplest of applications, it's the reason why a user can create, read, update, and destroy (CRUD) particular pieces of data.

The MVC Diagram

This is one of the many fundamental properties that Rails simplifies for us in web applications. The User sends a request to the Controller, which manipulates the request to be interpretable by the Model so it can update the View and present it back to the User.

What is REST?

REST is REpresentational State Transfer which references an architectural design flow/pattern when routing your HTTP requests. Often times, requests like GET, POST, etc are used more than once for a certain controller and the definitions for each varying GET or POST request will look and execute messily. To avoid this, the rails backend structures 7 specific route names that translate the HTTP request smoothly once defined in the specific controller.

For example, a lot of GET requests without this convention are written in Sinatra with

class ApplicationController < Sinatra::Base

  get '/games' do
    games = Game.all
    games.to_json data
  end

end
Enter fullscreen mode Exit fullscreen mode

As you can see, to satisfy a simple SELECT * statement, a get request is used and must used over and over again to specific different types of get requests.

7 Common Rails Routes

Route Setup

In your routes.db in your Ruby application, this is where the specifications of the different routes per controller are defined.

Rails.application.routes.draw do
   resources :games
end
Enter fullscreen mode Exit fullscreen mode

Having no particular declarations after the :games attribute has rails interpret all 7 routes to be implemented. If you only wanted to have a CREATE route, then you would add

Rails.application.routes.draw do
   resources :games, only: [:create]
end
Enter fullscreen mode Exit fullscreen mode

Index | Show

Index and Show in a RESTful context both reference the GET HTTP pull method. Index would list the entire index of a certain table, and Show would represent only one row of that table

In routes.db, further clarification is needed

Rails.application.routes.draw do
   resources :games, only: [:index, :show]
end
Enter fullscreen mode Exit fullscreen mode

In the controller for the respective class (in this case, a game_controller.rb file), the implementation is

class GameController < ApplicationController
   def index
      render json: Games.all
   end
end
Enter fullscreen mode Exit fullscreen mode

Here, we tell the database to get all indices of a table and render them back to the Model
You can also tack on a status code if need be

render json: Games.all, status: :ok

Show represents the GET HTTP method as well, but with a parameter (typically an ID of the index you'd like)

def show
   render json: Games.find(params[:id]), status: :ok
end
Enter fullscreen mode Exit fullscreen mode

If you need to cover for the situation in which the ID wasn't found then you can nest it in an if-else scenario

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

Create | Update | Destroy

Once again we specify our routes.db to include these HTTP requests

Rails.application.routes.draw do
   resources :games, only: [:index, :show, :create, :update, :delete]
end
Enter fullscreen mode Exit fullscreen mode

When creating entries, rails can not automatically assume the contents of a POST request, we need to re-orient the parameters so that the body of the post request can be interpreted to create new entries
Adding this wrap_parameters declaration tells rails to re-format the data into a [] array-like format, so that we can break apart what was sent and see if there are extra, or lacking pieces of data

class GameController < ApplicationController
wrap_parameters format: []
Enter fullscreen mode Exit fullscreen mode

The CREATE request is defined as follows

def create
   game = Games.create(game_params)
   render json: game, status: :created
end

private
def game_params
   params.permit(:name, :publisher, :release_year, :console)
end
Enter fullscreen mode Exit fullscreen mode

The game_params function takes the params and assigns each attribute to be returned as parameters, so it is properly formatted when passed into the create function

Update would replicate the show route but with a small change when rendering

def update
   game = Games.find(params[:id])
   if game
      game.update(game_params)
      render json: game, status: :accepted
   else
      render json: {error: "Game not found"}, status: :not_found
   end
end
Enter fullscreen mode Exit fullscreen mode

Destroy would be similar to above as well, the only niche is that since there isn't necessarily any data to render back to the Model, you would return head :no_content

def destroy
   game = Games.find(params[:id])
   if game
      game.destroy
      head :no_content
   else
      render json: {error: "Game not found"}, status: :not_found
   end
end
Enter fullscreen mode Exit fullscreen mode

Conclusion

Overall, as fundamentally standard CRUD is across all forms of database management/administration, the only extra step needed when adapting to new environments is following the conventions. New and Edit would require a form to be presented and rendered, in which case the Create and Update definitions would be invoked afterwards.
Happy CRUDing!

References

MVC: Model, View, Controller (https://www.codecademy.com/article/mvc)

ThoughtBot: REST Tutorial (https://thoughtbot.com/upcase/videos/rest)

RailsGuides: Rails Routing (https://guides.rubyonrails.org/routing.html)

MakandraCards: wrap_parameters for your API
(https://makandracards.com/makandra/46405-rails-wrap_parameters-for-your-api)

Top comments (0)