Last week we looked at defining routes in Ruby on Rails.
When a request enters your application, the router will parse the URL path and dispatch the request to the relevant Controller.
The Controller forms an important part of the MVC (Model-View-Controller) design pattern and so Controllers are an integral part of a Ruby on Rails application.
In today’s tutorial we are going to be looking at the role of the Controller in a typical Ruby on Rails project.
What is the role of the Controller?
The Controller has a very simple, yet very important role in the MVC design pattern.
It is the Controller’s responsibility to accept a request and dispatch a response from the application.
This will usually involve talking to the model layer to gather the required data for the request, and then returning an appropriate response, typically HTML or JSON in most Rails applications.
The Controller has a very narrow set of responsibilities and so as a developer you should stick to these conventions and not let extra responsibility leak into your Controllers.
Creating a Controller in Rails
As with just about every other aspect of Rails, there are already a lot of conventions around how you should structure your Controllers.
Firstly, your Controllers should live under the
As we saw in last week’s tutorial, if you have nested routes you will need to create nested directories to house these controllers.
Your Controller should be named by pluralising the last word, such as
Although as with most other things in Rails, you can override this convention, your life will be a lot easier if you just follow it.
By default your routes will automatically know which Controller to dispatch the request to if you have named it according to the convention.
Finally, each of your Controllers should inherit from
class UsersController < ApplicationController end
Defining Controller Methods
In last week’s tutorial we created routes for the
:articles resource. When an article request enters your application, Rails will create a new instance of the
ArticlesController and call the appropriate method.
This means we need to define those methods in order for the request to work.
class ArticlesController < ApplicationController def index # Return all articles end end
Your Controllers are basically just normal Ruby objects but with inherited functionality from the
Whilst resource routes will have predefined method names, you are free to create any other public methods that can be dispatched to from a HTTP request
If you have any helper methods on your Controllers, it’s best practice to have them as
protected so they can’t be dispatched to.
One of the main responsibilities of your Controllers is to accept requests. An HTTP request will usually have parameters in one form or another.
For example, a request like
users/123 will pass
123 as the
A request like
users?sort=name will pass the
sort column as the parameter.
POST request will send a payload of parameters in the body of the request.
Rails allows you to get access to these parameters using the
For example here is a Controller method to display a user by their id:
def show @user = User.find(params[:id]) end
And here is an example of a Controller method to create a new user:
def create @user = User.new(params[:user]) if @user.save redirect_to @user else render 'new' end end
Working with Sessions
A second important responsibility of the Controller is to work with the application’s session.
By default, HTTP requests are stateless. In order to have functionality such as the ability to be authenticated, we need a way to persist data between requests.
Each session has a unique id so we can store data in the session for that user.
Rails has a whole load of configuration options and different storage mechanisms for dealing with Sessions, but we will look deeper into that area of the framework in a future tutorial.
To access the session, you can use the
session instance method that can be handled like a hash.
For example, when a user authenticates with your application, you will want to store the user’s id between requests. To do this we can put it in the session:
class SessionsController < ApplicationController def create if user = User.authenticate(params[:username], params[:password]) session[:current_user_id] = user.id redirect_to root_url end end end
Now whenever a request enters your application, you can ensure that the user is authenticated by accessing the user’s id from the session and retrieving the user from the database:
class ApplicationController < ActionController::Base private def current_user @_current_user ||= session[:current_user_id] && User.find_by(id: session[:current_user_id]) end end
Finally, when it’s time to log the user out, you can send a
DELETE request to your
class SessionsController < ApplicationController def destroy @_current_user = session[:current_user_id] = nil redirect_to root_url end end
In this example I’m simply removing the value from the session by setting it to
Displaying Flash Messages
A flash message is a message that is displayed to the user for one request.
For example, you might want to display a message to say they successful created a new Article, logged out successfully, or that they should be expecting an email soon.
Flash messages are stored in the session for one request only. You don’t need to clear the flash message after it has been displayed as Rails will automatically take care of this for you:
class SessionsController < ApplicationController def destroy @_current_user = session[:current_user_id] = nil flash[:notice] = 'You have successfully logged out.' redirect_to root_url end end
Now you can display this flash message in your View like this:
<% if flash[:notice] %> <p class="notice"><% flash[:notice] %></p> <% end %>
Controllers form an important part of the MVC pattern. The Controller’s responsibility is very narrow, but extremely important in the grand scheme of a web application.
The Controller should accept requests, send the appropriate messages, and then return a response.
In today’s tutorial we’ve mostly looked at how Controllers can be used to accept requests and return responses for traditional web applications.
But Controllers are also an important part of accepting and return API requests and responses.
In a future tutorial we will be looking at how to deal with JSON, or XML requests as responses, but it’s basically the same!