Snow White & the 7 RESTful Routes
All Good Things Come in Sevens?
Snow White had her 7 dwarves. A week has 7 days. Christians have 7 deadly sins. . . And programmers have 7 RESTful routes!
Rest is good for your personal health and well-being, whereas REST is good for the understandability and usability of your CRUD app (an app that can Create, Read, Update, and Delete data). In the context of web development, REST stands for Representational State Transfer and refers to a set of guidelines for html verb + url combinations and their designated actions.
Following these RESTful conventions makes it easier for developers to be on the same page. Since these routes are the same/similar for all CRUD apps, it’s easier for other developers to understand what your app is doing if you follow these conventions as well.
There are 7 routes for CRUD verbs and actions. These routes are:
get “/models” => “controller#index”
# Shows all instances of your modelget “/models/new” => “controller#new”
# Shows form to create new instancepost “/models“ => “controller#create”
# Creates new instance from new formget “/models/:id” => “controller#show”
# Shows individual instance (id#)get “/models/:id/edit” => “controller#edit”
# Shows form to edit specific instancepatch “/models/:id” => “controller#update”
# Updates instance from Edit formdelete “/models/:id” => “controller#destroy”
# Removes instance from database
The beauty of following these conventions is that you don’t have to reinvent the wheel every time you build a new CRUD app. The routes and method names have already been decided, so you can just focus on the app itself.
Since all CRUD apps are capable of doing the same four basic actions, these routes can be used for all your projects. I’ll go through each of the CRUD actions one by one, and how each of the RESTful routes accomplishes each action.
For the purpose of this blog, I’ll refer to the CRUD actions with capital letters (Create, Read, Update, and Delete), whereas I’ll refer to the RESTful routes with a #hash symbol and the name of its method (#index, #new, #create, #show, #edit, #update, and #destroy). Hopefully that’ll make it easier to tell when I’m talking about an action, a route, or just describing things!
Once these routes are implemented in your app, you no longer have to use the terminal to update your database! You can do all your database updates within your app itself!
CRUD Action: Create
Within the RESTful routes, two routes are designed to work in conjunction to create a new instance of a model and save it to the database.
The #new route simply shows a form for the user to fill out, while the #create route takes the user inputs and adds the information to the database.
The code for these two routes are:
get “/models/new” => “controller#new”
# Shows form to create new instancepost “/models“ => “controller#create”
# Creates new instance from new form
#new RESTful Route
When the user sends a get
request to /models/new
, it triggers the #new route, which simply shows a form for the user to fill out. The code for the new
method is:
def new
render “new.html.erb”
end
To activate this route, the user simply visits the web address of the form by typing the url into the browser or (more likely) clicking a link. This sends the get request to the /models/new
url. The user then fills out the form, but the new instance of the model will not be created until the user submits the form.
The code for the form will look something like:
<%= form_tag “/models”, method: :post do %>
<div>Attribute1: <input type=”text” name=“input1”></div>
<div>Attribute2: <input type=”text” name=”input2"></div>
<div><input type=”submit” value=”Create New Instance”></div>
<% end %>
In Rails, a Rails form_tag
must be used rather than a usual html tag. It does the exact same function as the html tag, but with some added security to prevent hackers from sending false information through the form.
When the user hits the submit button on the form, this will save the attributes as parameters with the names given in the form. It will also send a post request to the /models
URL.
#create RESTful Route
Once a post request is sent to the /models
url, the #create route is triggered. The create
method in the controller file is where all the code exists to take the user-inputted parameters and save them to the database. For the above example, the code for the create method will look like:
def create
new_instance = Model.new(
attribute1: params[“input1”],
attribute2: params[“input2”]
)
new_instance.save
flash[:success] = “New Instance Successfully Saved!”
redirect_to “/models”
end
This method
- creates a new instance of the model,
- populates the instance with the attributes that the user filled out in the “Create New Instance” form,
- saves the new instance, and
- redirects the user to the main “/models” route while alerting the user that their instance was created.
CRUD Action: Read
There are also two RESTful routes that allow us to read the data in our database. Unlike the Create methods, however, these routes function independently of each other. Rather than one route being generated by and receiving information from another route, they just show the same information in two different ways.
The two routes allowing us to read data are:
get “/models” => “controller#index”
# Shows all instances of your modelget “/models/:id” => “controller#show”
# Shows individual instance (id#)
#index RESTful Route
As noted in the comments, the first route will render a page that shows all instances of the model. To do this, the method just calls an array of all the instances, and saves it as an instance variable:
def index
@models = Model.all
render “index.html.erb”
end
The html file can contain as much or as little information about each instance as you want. The main job of the index page is to list all the instances, and have a link to another page which will show more information for one particular instance.
To display all the instances and create a customized link for each particular link, we need to embed Ruby code into the HTML in order to loop through the @models array that was created in the controller. Here’s an example of what the HTML file might look like for a simple page that only lists the name of the instance, with a link to the instance’s #show
page:
<% @models.each do |model| %>
<a href=“/models/<%= model.id %>”><%= model.name%></a>
<% end %>
The link to the individual product would then display additional information about the instance!
#show RESTful Route
The #show
route utilizes URL segment parameters to allow us to build a single template that will display each instance in our database individually. In order for the correct page to be loaded containing the information for one specific instance, the controller method must first find the instance with the correct id, and return that instance only. The code for this looks like:
def show
@product = Product.find_by(id: params[“id”])
render “show.html.erb”
end
where id:
refers to the id attribute that Rails assigns each instance of a model, and “id”
is the url segment parameter :id
of the #show
route. This url segment parameter was defined in our index page as a link for the individual instance.
It’s definitely a daunting task keeping track of where similarly-named variables are coming from, but this type of attention to detail is very important when it comes to programming!
The “show.html.erb”
file would then contain html to display all the information about the specific product. Here’s a basic example of what this code would look like:
<h1><%= model.name %></h1>
<h2><%= model.attribute1 %></h2>
<h3><%= model.attribute2 %></h3>
Obviously, there would be more html on this page to make it look nicer (perhaps using Bootstrap?) But the idea is that this page should display all the information you want the user to be able to see. The user would get to this page by clicking on the appropriate link in the Index page.
CRUD Action: Update
Similar to Create, there are two RESTful Routes that work in conjunction to perform the Update CRUD action.
The #edit route simply displays a form for the user to fill out, while the #update route takes the parameters from the form and actually updates the existing database instance.
get “/models/:id/edit” => “controller#edit”
# Shows form to edit specific instancepatch “/models/:id” => “controller#update”
# Updates instance from Edit form
The #edit
and #update
routes work very similarly to the #new
and #create
routes. In fact, the code will be very similar except for a few small changes.
#edit RESTful Route
The job of the #edit
route is simply to show a user a form to fill out. However, since we are editing an existing instance, it must first find the instance so that the app knows which instance we’re editing. The code for the controller#edit
method would look like:
def edit
@model = Model.find_by(id: params[:url_segment_id])
render “edit.html.erb”
end
To activate this route, the user just visits /models/:url_segment_id/edit
, where :url_segment_id
is a URL segment parameter that refers to the id of the instance. Note: you can make the URL segment parameter any attribute in the database, but it’s best to use the id since that is unique to each instance. Also, it’s generated and managed by Rails, so we can’t accidentally mess with it and ruin our links!
The edit.html.erb
file that the edit
method renders will be a form similar to the one we used in create.html.erb
. The main differences are:
- The action of the Submit button will be
patch “/models/:id”
- The form will be pre-filled with the existing information in the database, so the user can just edit what’s already there, or leave it alone if not all attributes will be updated.
An example of the code for the html page:
<%= form_tag “/models/#{@model.id}”, method: :patch do %>
<div>Attribute1:
<input type=”text” name=“input1”
value=“<%= @model. attribute1 %>”>
</div>
<div>Attribute2:
<input type=”text” name=“input2”
value=“<%= @model. attribute2 %>”>
</div>
<div><input type=”submit” value=“Update this Instance”></div>
<% end %>
When the user hits the Submit button for this app, it will send a Patch request to /models/:url_segment_id
and save the attributes into the params hash.
#update RESTful Route
Once a patch request is sent to the /models/:url_segment_id
url, the controller#update
route is triggered. Just like the “create” method, the “update” method in the controller file is where all the code exists to take the user-edited parameters and save them to the database. For the previous example, the code for the create method will look like:
def create
@model = Model.find_by(id: params[:url_segment_id]
@model.attribute1 = params[“input1”]
@model.attribute2 = params[“input2”]
@model.save
flash[:success] = “Instance Successfully Updated!”
redirect_to “/models/#{@model.id}”
end
This method
- finds the existing instance based on the parameter listed in the url segment parameter
- updates all the attributes based on the user input from the Edit. Note that if the user didn’t edit a field, it will just save the exact same value.
- saves the instance
- redirects the user back to the #show page while alerting the user that their instance was update.
CRUD Action: Delete
Delete is the most straightforward of the CRUD actions and is therefore the only CRUD action that one uses one route.
This route simply find the desired instance, and runs the .destroy method on it. Rather than rendering its own unique html page, it just redirects the user back to the index route while displaying a message saying the action was successful.
#destroy RESTful Route
The route for the Destroy action is:
delete “/models/:id” => “controller#destroy”
As with the post
and patch
requests that the #create
and #update
routes employed, the delete
request cannot be submitted simply by clicking a link or visiting a website (these only send get
requests). Instead, the appropriate request is submitted using a form.
However, unlike the create and update routes, for there aren’t any user inputs for the delete route besides simply clicking the Submit
button, which in this case will be labeled Delete
.
The code for this would be placed on another html page — perhaps the Edit page as a secondary button option apart from submitting the form or returning to the main page. It can even be made as an option in a pop-up window so that you have have the page display a warning before giving them access to the Delete button (more on how to do this in a future post!)
In any case, the code for the delete button is:
<%= form_tag “/models”, method: :delete do %>
<div><input type=”submit” value=“Delete”></div>
<% end %>
You can also use a link_to
or button_to
tag rather than a form_tag
tag.
Once the user clicks on the delete button, it sends a Delete request to “/models”, which activates the Destroy method. The method for the Destroy action is:
def destroy
instance = Model.find_by(id: params[:id])
instance.destroy
flash[:warning] = “Instance Successfully Deleted!”
redirect_to “/index”
end
Since the instance will be deleted by the time the method reaches the end, there isn’t much to display, so the above code simply takes the user back to the index while displaying a message saying the item was deleted.
These seven routes serve as the foundation of any CRUD app. Following these conventions will allow you to set up a new app quickly and easily.
Not having to think about how to set up your routes and pages will allow you to focus your attention on the app itself and customize it to your needs.
Someone else already invented the wheel; no need to reinvent it! Use the structure that already exists so you can focus on more important aspects of your app!