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.

Anatomy of a Rails Application, Part I: Views

Ruby on Rails is a framework for building web applications that allows developers to create back-end database systems quickly. My favorite part of Rails is that it integrates the visual presentation of back-end data easily. Learning how to control databases in general without any visuals can be tricky, so we'll start today by looking at Rails and setting up these visuals the Rails way. Theses visuals are called "views," and written mostly in HTML, with some special Ruby sauce mixed in. Rails gives us some tools using the Ruby language to beef up what we can do in our views. Let's take a look.

This post is the first of a multi-part series on building a Rails application.

alt Introducing PowerUp, a workout logging web application using Rails, MongoDB, and Bootstrap.

There are many resources available for setting up a Rails application from scratch, such as Daniel Kehoe's excellent book, Michael Hartl's tutorial, and the Rails video lesson series at CodeSchool. This series will jump into writing code on a live application.

PowerUp is an application that allows users to log their workouts. PowerUp's views have to provide a visual interface for the following tasks:

  • Create a new user through a signup form
  • Log in an existing user to the site
  • Edit the user's information
  • Create a new workout log
  • Edit the details of a particular workout log
  • Delete a workout from a user's list of workouts.

Rails knows that, in order for our views to display properly in a browser, the html code must be formatted a ceratin way. Rails takes care of part of this issue for us by providing a default page layout, in which other views of our app will show. This default piece is a file called application.html.erb:

<!DOCTYPE html>  
    <html>
        <head>
            <title>PowerUp</title>
            <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
            <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
            <%= csrf_meta_tags %>
        </head>
        <body>
            <%= yield %>
        </body>    
    </html>

The application.html.erb file gives us all of the doctype, html, head, and body tags without any additional configuration. These nice built-in defaults are a theme of developing applications with Rails. On this page, the <%= yield %> tag is a sort of placeholder. Rails puts whichever view is needed in place of the yield tag, and the resulting page is still clean, seamless HTML. For example, if one of our views consisted of the following code:

<h1>This is an example page</h1>  
<p>I'll show up in place of the yield tag, just watch</p>  

The browser would render this:

<!DOCTYPE html>  
    <html>
        <head>
          <title>PowerUp</title>
          <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
          <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
          <%= csrf_meta_tags %>

        </head>
        <body>

            <h1>This is an example page</h1>
            <p>I show up in place of the yield tag, just watch</p>

        </body> 
    </html>

This example is the most basic way in which Rails keeps our code DRY (Don't Repeat Yourself). The yield tag inserts only code that is changing in the HTML, keeping us from having to write the other page tags over and over for each page that the application renders in the browser.

Another tool that helps developers write DRYer code in Rails is view partials. Partials are code chunks that can be called in as many places in your application as needed. In PowerUp, the form used to create a new workout log and edit existing logs is identical. So we'll write a form partial and save is as _form.html.erb within the views/workouts folder.

First, we'll access the form partial in the new workout view, with some Bootstrap styling, like so:

<div class="col-sm-4 col-sm-offset-4">  
    <h1>Edit</h1>
    <%= render "workouts/form" %>
</div>  

Notice how the render calls the 'form' partial from the 'workout' folder. Saving the partial with this specific file path is important. It is likely that there will be other forms in other parts of your Rails application, and the only way to distinguish them when using the render tag is by specifying which folder in which to access the partial. The render tag helps keep code DRY by allowing changes to a single file to be accessed throughout the application.

Having DRY code is awesome and all, but what if we want smart code as well? What if I want to provide PowerUp users links to their profile and log out, but only when they are logged in? Rails gives us a way to do change content based on certain conditions by allowing Ruby code in our views.

First is our navbar links when a user is not logged in:

alt No user logged in, static links.

Here's the code for static links:

<li><%= link_to "Log In", new_session_path %></li>  
<li><%= link_to "Sign Up", new_user_path %></li>  

Pretty straighforward, but these links will always stay the same. Not useful when a user is logged in. We want the user to have access to these links:

alt User logged in, dynamic links

Rails lets us write Ruby code into our views. Let's use an if statement to check if a user is logged in, and show the appropriate links based on this check:

<% if logged_in? %>  
        <li class="active"><%= link_to "Welcome, #{current_user.name}!", user_path(current_user) %> </li>
        <li><%= link_to "Profile", user_path(current_user) %> </li>
        <li><%= link_to 'Log Out', logout_path, method: :delete %></li>
    <% else %>
        <li><%= link_to "Log In", new_session_path %></li>
        <li><%= link_to "Sign Up", new_user_path %></li>
<% end %>  

Now our navbar links will change based on the user's needs. This dynamic content concept can be used in many different ways; error messages, vote/comment counters, and other permission-based content restrictions.

Rails gives developers a few methods for presenting data and information in a flexible way. Yield tags, partials, and even straigh Ruby code are all tools that developers can use to build attractive and useful views in their Rails applications. Try some of these techniques in your next app and see what you can build.