1. Technology
You can opt-out at any time. Please refer to our privacy policy for contact information.

What is a Controller?

By

What is a Controller?

Ruby on Rails is an MVC framework. Your web applications are written by composing models, views and controllers. For many Rails newbies, models and views are easy to understand. Models deal with the data, they make SQL queries and give you Ruby objects (and vice versa). Views are familiar to anyone who has done any web development before, they produce the output. But what are the controllers? Why do we even need them, can't the views just access the models directly?

A controller is where distinct and related actions are collected. For example, a "Post" controller in a blog application is where all actions related to blog posts are kept. In this controller there are methods to create a new post, edit a post, view a post, destroy a post, etc. A controller can be thought of as an API. Where models are a lower level way to access data, and views present a user interface, controllers are the APIs that make sense out of everything.

A controller is the glue that holds the model and view together. Ideally, a model shouldn't know anything about the view. In fact, the model should be able to operate without the view at all, and often does during tests. The view shouldn't have to know about the model either. The view just produces output, it shouldn't know where the data is coming from. The controller is what sits in between. The controller gets data from the model and gives it to the view. The controller knows about both the model and the view, but neither the model or view know anything about the other parts. The controller is unique in this way.

A controller is where things happen. The model is concerned with data, with data integrity, but often has no concept of how the data is used. It has no idea it's even a web application, it has no idea there are users that must authenticate first, or about many of the calculations and ways data is massaged before and after the model is involved. Many tasks have the controller doing complex actions (such as collating data and doing statistical analysis on it), it's where if there is anything to happen actually happens. (Though, as an aside, many believe the controller should be a small as possible, this is often referred to as the "fat model, skinny controller" approach.)

A controller is both the entry point of a request and exit point of a response. When a request comes into your Rails application, it first goes to the router whose sole job is to decide which controller (and which action of that controller) the request belongs to. The request then passes to the controller, which will use data from the model and a template from the view to generate output. The controller is then the exit point of the response, as the controller sends it back to the web server. In this way, the controller is where all flow control of a request happens within your Rails application.

A controller is a filter. Before or after any action is run, the controller will prevent anything unauthorized, bad or nonsensical from happening by using "before filters" and "after filters." This is where things like authentication and authorization happens, so security-wise the controller is an important piece.

What Does A Controller Look Like?

A controller is really just a class. It usually inherits from your "application controller," a class called ApplicationController you can find in app/controllers/application_controller.rb. Normally this file is virtually empty, just a class declaration that inherits from ActionController::Base and (in the current version) contains a single call to protect_from_forgery, which installs a before filter for CSRF protection.


class ApplicationController < ActionController::Base
  protect_from_forgery
end

Here is the truncated code for a functional controller. The controller name is important, it's the name referenced by app/config/routes.rb and what methods all over the Rails application refer to when they want to talk about this specific controller. Each public instance method of the controller class is an action. Each action is mapped to a URL. In this way, a controller is simply a way to call specific actions within your Rails application from a URL. Note that most of the methods do rather simple things. They do something with a model (they create a new object, read one from the database or write one to the database) and they generate output. Very little else is done in many controllers, especially ones that are generated using the scaffold generator.

Also note the before filter at the top. In this case, it uses Devise to make sure the user is logged in except for two methods (index and show, which only read posts). Also, most of the actions render more than one type of input. This is so you can produce HTML output for a full page request, or JSON output for an AJAX request. You'll also see output for things like RSS produced in a similar manner.


class PostsController < ApplicationController
  before_filter :authenticate_user!, :except => [:index, :show]
  
  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @posts }
    end
  end

  # GET /posts/1
  # GET /posts/1.json
  def show
    @post = Post.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @post }
    end
  end

  # GET /posts/new
  # GET /posts/new.json
  def new
    @post = Post.new
    @post.user = current_user

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @post }
    end
  end

  # GET /posts/1/edit
  def edit
    @post = Post.find(params[:id])
  end

  # POST /posts
  # POST /posts.json
  def create
    @post = Post.new(params[:post])

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render json: @post, status: :created, location: @post }
      else
        format.html { render action: "new" }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /posts/1
  # PUT /posts/1.json
  def update
    @post = Post.find(params[:id])

    respond_to do |format|
      if @post.user != current_user
        format.html { redirect_to @post, notice: 'That post is not yours to edit' }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      elsif @post.update_attributes(params[:post])
        format.html { redirect_to @post, notice: 'Post was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /posts/1
  # DELETE /posts/1.json
  def destroy
    @post = Post.find(params[:id])
    
    if @post.user != current_user
      flash[:notice] = 'That post is not yours to destory'

      respond_to do |format|
        format.html { redirect_to :back }
        format.json { head :no_content }
      end
    else
      @post.destroy

      respond_to do |format|
        format.html { redirect_to posts_url }
        format.json { head :no_content }
      end
    end
  end
end

  1. About.com
  2. Technology
  3. Ruby
  4. Ruby on Rails
  5. What is a Controller?

©2014 About.com. All rights reserved.