# Controller

Controllers can group related request handling logic into a single class. For example, a **UserController**class might handle all incoming requests related to users, including showing, creating, updating, and deleting users. By default, controllers are stored in the **app/Controllers**directory.

  • Writing Controller

    • Controller Naming Convention

      The naming convention of controllers in Rails favors pluralization of the last word in the controller's name, although it is not strictly required (e.g. ApplicationController). For example, ClientsController is preferable to  ClientControllerSiteAdminsController  is preferable to  SiteAdminController  or  SitesAdminsController, and so on.

      Following this convention will allow you to use the default route generators (e.g. resources, etc) without needing to qualify each :path or :controller, and will keep named route helpers' usage consistent throughout your application.

    • Basic Controllers

      A controller is a Ruby class which inherits from ApplicationController  and has methods just like any other class. When your application receives a request, the routing will determine which controller and action to run, then Rails creates an instance of that controller and runs the method with the same name as the action.

      class ClientsController < ApplicationController
        def new
        end
      end
      
      1
      2
      3
      4

      As an example, if a user goes to /clients/newin your application to add a new client, Rails will create an instance of ClientsControllerand call its newmethod. Note that the empty method from the example above would work just fine because Rails will by default render the new.html.erbview unless the action says otherwise. By creating a new Client, the newmethod can make a @client instance variable accessible in the view:

      def new
        @client = Client.new
      end
      
      1
      2
      3
  • Controller Filters

    Filters are methods that are run "before", "after" or "around" a controller action.

    Filters are inherited, so if you set a filter on ApplicationController, it will be run on every controller in your application.

    • Before

      "before" filters are registered via before_action. They may halt the request cycle. A common "before" filter is one which requires that a user is logged in for an action to be run. You can define the filter method this way:

      class ApplicationController < ActionController::Base
        before_action :require_login
      
        private
      
        def require_login
          unless logged_in?
            flash[:error] = "You must be logged in to access this section"
            redirect_to new_login_url # halts request cycle
          end
        end
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12

      The method simply stores an error message in the flash and redirects to the login form if the user is not logged in. If a "before" filter renders or redirects, the action will not run. If there are additional filters scheduled to run after that filter, they are also cancelled.

      In this example, the filter is added to ApplicationController and thus all controllers in the application inherit it. This will make everything in the application require the user to be logged in to use it. For obvious reasons (the user wouldn't be able to log in in the first place!), not all controllers or actions should require this. You can prevent this filter from running before particular actions with skip_before_action:

      class LoginsController < ApplicationController
        skip_before_action :require_login, only: [:new, :create]
      end
      
      1
      2
      3
    • After Filters and Around Filters

      In addition to "before" filters, you can also run filters after an action has been executed, or both before and after.

      "after" filters are registered via after_action. They are similar to "before" filters, but because the action has already been run they have access to the response data that's about to be sent to the client. Obviously, "after" filters cannot stop the action from running. Please note that "after" filters are executed only after a successful action, but not when an exception is raised in the request cycle.

      "around" filters are registered via around_action. They are responsible for running their associated actions by yielding, similar to how Rack middlewares work.

      For example, in a website where changes have an approval workflow, an administrator could preview them easily by applying them within a transaction:

      class ChangesController < ApplicationController
        around_action :wrap_in_transaction, only: :show
      
        private
      
        def wrap_in_transaction
          ActiveRecord::Base.transaction do
            begin
              yield
            ensure
              raise ActiveRecord::Rollback
            end
          end
        end
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15

      Note that an "around" filter also wraps rendering. In particular, in the example above, if the view itself reads from the database (e.g. via a scope), it will do so within the transaction and thus present the data to preview.

      You can choose not to yield and build the response yourself, in which case the action will not be run.

  • Controller Generation

    Using generators will save you a large amount of time by writing boilerplate code , code that is necessary for the app to work.

    Let's make our own controller with the controller generator. But what command should we use? Let's ask the generator:

    bin/rails generate controller
    
    Usage: bin/rails generate controller NAME [action action] [options]
    
    ...
    ...
    
    Description:
        ...
    
        To create a controller within a module, specify the controller name as a path like 'parent_module/controller_name'.
    
        ...
    
    Example:
        `bin/rails generate controller CreditCards open debit credit close`
    
        Credit card controller with URLs like /credit_cards/debit.
            Controller: app/controllers/credit_cards_controller.rb
            Test:       test/controllers/credit_cards_controller_test.rb
            Views:      app/views/credit_cards/debit.html.erb [...]
            Helper:     app/helpers/credit_cards_helper.rb
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22

    The controller generator is expecting parameters in the form of generate controller ControllerName action1 action2. Let's make a Greetingscontroller with an action of hello , which will say something nice to us.

    bin/rails generate controller Greetings hello
    
         create  app/controllers/greetings_controller.rb
          route  get 'greetings/hello'
         invoke  erb
         create    app/views/greetings
         create    app/views/greetings/hello.html.erb
         invoke  test_unit
         create    test/controllers/greetings_controller_test.rb
         invoke  helper
         create    app/helpers/greetings_helper.rb
         invoke    test_unit
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a view file, a functional test file, a helper for the view, a JavaScript file, and a stylesheet file.

    Check out the controller and modify it a little(in app/controllers/greetings_controller.rb ):

    class GreetingsController < ApplicationController
      def hello
        @message = "Hello, how are you today?"
      end
    end
    
    1
    2
    3
    4
    5

    Then the view, to display our message (in app/views/greetings/hello.html.erb):

    <h1>A Greeting for You!</h1>
    <p><%= @message %></p>
    
    1
    2

    Fire up your server using bin/rails server.

    bin/rails server
    
    Booting Puma...
    
    1
    2
    3

    The URL will be http://localhost:3000/greetings/hello (opens new window).