RESTful Routes in Rails
Tags: ruby, rails, database
Published: 2021-05-09 06:39:47

Routes are how requests, through URL and HTTP method, are directed to code that handles the routes. RESTful, Representation State Transfer, routes is a more structured way of defining how our routes work. RESTful routes provide mapping between HTTP verbs, controller actions, and CRUD operations in a database. CRUD represents an acronym for the database operations Create, Read, Update, and Delete (or Destroy). The controller actions, or CRUD, respond to the HTTP verbs, which are GET, POST, PUT and DELETE, as seen in the table below.

<table>
  <tr> 
    <th>HTTP Verb</th>  
    <th>Path</th>
    <th>Controller#Action</th>
    <th>Used for</th>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts</td>
    <td>posts#index</td>
    <td>display all posts</td>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts/new</td>
    <td>posts#new</td>
    <td>return an HTML form for creating a new post</td>
  </tr>
  <tr>
    <td>POST</td>
    <td>/posts</td>
    <td>posts#create</td>
    <td>create a new post</td>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts/:id</td>
    <td>posts#show</td>
    <td>display a specific post</td>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts/:id/edit</td>
    <td>posts#edit</td>
    <td>return an HTML form for editing a post</td>
  </tr>
  <tr>
    <td>PATCH/PUT</td>
    <td>/posts/:id</td>
    <td>posts#update</td>
    <td>update a specific post</td>
  </tr>
  <tr>
    <td>DELETE</td>
    <td>/posts/:id</td>
    <td>posts#destroy</td>
    <td>delete a specific post</td>
  </tr>
</table>

In my Rails project for Flatiron, in addition to RESTful routes, I used nested resources. Resources syntax is a useful way to have Rails generate each of the seven RESTful routes for you.

```
# config/routes.rb
Rails.application.routes.draw do
  resources :posts
end
```
The `resources: posts` in our routes.rb file will give you the seven RESTful routes for your application. Now let's say my application has a comments model. A comment belongs to a post and a post has many comments. If I wanted a route to look at a posts comments, such as `/posts/1/comments`, I would need to utilize nested resources.

```
# config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments
  end
end
```

In our routes.rb file we nest comments resources under our posts resources to create some nested resources. Posts still gets the seven RESTful routes, while comments get seven NESTED RESTful routes.

<table>
  <tr> 
    <th>HTTP Verb</th>  
    <th>Path</th>
    <th>Controller#Action</th>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts/:post_id/comments </td>
    <td>comments#index</td>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts/:post_id/comments/new</td>
    <td>comments#new</td>
  </tr>
  <tr>
    <td>POST</td>
    <td>/posts/:post_id/comments</td>
    <td>comments#create</td>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts/:post_id/comments/:id</td>
    <td>comments#show</td>
  </tr>
  <tr>
    <td>GET</td>
    <td>/posts/:post_id/comments/edit</td>
    <td>comments#edit</td>
  </tr>
  <tr>
    <td>PATCH/PUT</td>
    <td>/posts/:post_id/comments/:id</td>
    <td>comments#update</td>
  </tr>
  <tr>
    <td>DELETE</td>
    <td>/posts/:post_id/comments/:id</td>
    <td>comments#destroy</td>
  </tr>
</table>

Nesting resources can get out of hand pretty quick, so best practice is to never nest more than 1 level deep (2 resources). The nested resources should have a parent/child relationship -- posts is the parent and comments is the child. Helpful tip: the last resource in the route is the controller that handles the requests. `/posts/:post_id/comments/new` the new action for creating a new comment belonging to a specific post will be handled in the comments controller. One thing to note, the nested child resource are NESTED RESTful routes. If you want routes such as `/comments/:id`, `/comments/new`, or `/comments/edit`, you must include comments resources in your config/routes.rb file to get non-nested RESTful routes for comments.

```
# config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments
  end
  resources :comments
end
```

In my project, I had itineraries nested under my destinations, so I wanted to be able to destroy all itineraries related to a destination.

```
# config/routes.rb
Rails.application.routes.draw do
  resources :destinations do
    resources :itineraries do
      delete: destroy_all, on: :collection
    end
  end
end
```
Adding `delete: destroy_all, on: :collection`, creates a destroy_all action in the itineraries controller where I can delete all the itineraries under the current destination_id that belong to the user. This is a helpful action that allows me to delete a collection, and save the `itineraries#destroy` route for deleting a single itinerary.

If you want to see the routes on your application you can run your server followed by `/rails/info/routes` or run `rails routes` in your terminal to display your current routes. Here is a guide on [nested resources](https://guides.rubyonrails.org/routing.html#nested-resource) for more information.

The Request/Response Flow uses RESTful routing. The user makes a request to a route. The application goes into the config/routes.rb to match the route to a controller/action. The logic in the action will be processed and the controller may interact with the model. Rails then renders the view associated with the action with the given data.