cult3

Creating Controllers in Ruby on Rails

Dec 16, 2015

Table of contents:

  1. What is the role of the Controller?
  2. Creating a Controller in Rails
  3. Defining Controller Methods
  4. Accepting Parameters
  5. Working with Sessions
  6. Displaying Flash Messages
  7. Conclusion

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 controllers directory.

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 UsersController or ProductCommentsController.

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 ApplicationController:

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 ApplicationController.

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 private or protected so they can’t be dispatched to.

Accepting Parameters

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 id parameter.

A request like users?sort=name will pass the sort column as the parameter.

Or a 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 params hash.

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 SessionsController:

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 nil.

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 %>

Conclusion

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!

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.