Anatomy of a Rails Application, Part II: Controllers

As we learned previously, Rails uses views to show back-end data to a user. How does a Rails application know what data to show? When is an index view rendered rather than a show view? How does Rails control all of this stuff? You guessed it, with controllers. Today we'll go over how a Rails application makes data and actions available to these views using controllers.

This post is the second in a multi-part series on building a Rails application. Check out part 1 here.

Let's look at how PowerUp uses controllers.

Here are some additional resources: CodeSchool's Rails tutorial series has a lesson dedicated to controllers. RailsGuides are typically my first stop for Rails questions, and they have an excellent section on how routes and controllers interact.

Organizing Rails apps with RESTful controllers

Because Rails is designed as a web application framework, setting up our application's actions is centered around using HTTP verbs (GET, PUT/PATCH, POST, DELETE) to keep our code organized. Rails conventions give us a way to accomplish our typical database actions (create, read, update, destroy, or CRUD) using HTTP verbs. Further down the line, our views and paths will also be organized around these actions. Here's a list of the actions using users as an example:

  • index method returns a list of all of the users. HTTP verb: GET.
  • show returns a specific user. Can be used to retrieve a user's info. HTTP verb: GET.
  • new returns a form for creating a new user. Is related to the create action. HTTP verb: GET.
  • create creates a new user by adding its record to the database. HTTP verb POST.
  • edit returns a form for changing a user's info in the database. Is related to the update action. HTTP verb: GET.
  • update changes a user's record in the database. HTTP verb: PUT/PATCH.
  • destroy deletes a user's record in the database. HTTP verb; DELETE.

Next, let's generate a controller and start writing some Ruby code.

Generating the Controller in Rails

A Rails application makes it easy to generate controllers quickly. To do so, go to your terminal and first make sure you are in your application's directory (this gets me every time). Next, enter the following command:

rails generate controller users index

Let's break this command down to see what's happening. We are telling Rails to create a controller (not a model, which is the other option), to name it users, and to create an action in the controller called index as a Ruby method. While Rails can create these actions for us, we will always have the option of writing additional Ruby methods in any controller we generate.

We should now have two new files in our Rails app; app/controllers/users_controller.rb and app/views/index.html.erb. The ERB view file should be familiar from our previous look at Rails views. If we open the users_controller.rb, it should look like this:

class UsersController < ApplicationController  
  def index

  end
end  

This file is now our blank slate. From the controller, a Rails developer directs how information in the application is stored and rendered, and can direct how a user navigates the application.

Let's look at how some of the actions we previously defined would be implemented in our users controller. Here's the index action:

def index  
  @users = User.all
end  

The index defines the instance variable @users so that we may access this list of all users later on in the application, typically in the index.html.erb view. This is the most basic RESTful controller action, but wouldn't it be nice if we could create a new user as well? How would we write that action so it handles the database create AND the rendering of a specific path? With a little Ruby knowledge and a some Rails magic, we can write all of this in one method. Let's take a look:

def create  
  @user = User.new(user_params)  
  if @user.save    
    redirect_to user_path(@user), :notice => "Thanks for signing up! Here's your profile page."  
  else    
    render :new  
  end
end  

What's going on here? The create method is handling a few things for us:

  • Defining @user as a new user.
  • Checking if an attempt to save the user record is succssful. If it is, taking the user to the user show view (a "user profile"), and showing a confirm notice
  • If the attempt fails, redirecting back to the user new form.

The Rails magic in this method comes from the helpers like redirect_to, user_path, and render. The redirect_to helper does exactly what it says: redirects the user to a specific view. The user_pathis particular to the user show view, but you'll see that all of your application's view have some sort of _path helper assigned to it. Enter rake routes in your terminal to see a list of all of the available view paths. The render helper is another way to point to a particular view.

alt

A successful new user signup using the create method.

While we've gone over two of the RESTful actions in a Rails controller, they are others to consider when building your Rails application. Try writing the controller methods for some of the actions and see what you come up with. A typical Rails app will have at least one resource that has "full CRUD," or uses all of the controller actions. We'll explore Rails models and how they fit in with our controllers and views in the next installment.