# 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 toClientController
,SiteAdminsController
is preferable toSiteAdminController
orSitesAdminsController
, 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
4As an example, if a user goes to
/clients/new
in your application to add a new client, Rails will create an instance ofClientsController
and call itsnew
method. Note that the empty method from the example above would work just fine because Rails will by default render thenew.html.erb
view unless the action says otherwise. By creating a newClient
, thenew
method 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
12The 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 withskip_before_action
:class LoginsController < ApplicationController skip_before_action :require_login, only: [:new, :create] end
1
2
3After 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
15Note 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
22The controller generator is expecting parameters in the form of
generate controller ControllerName action1 action2
. Let's make aGreetings
controller 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
12What 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
5Then the view, to display our message (in
app/views/greetings/hello.html.erb
):<h1>A Greeting for You!</h1> <p><%= @message %></p>
1
2Fire up your server using
bin/rails server
.bin/rails server Booting Puma...
1
2
3The URL will be http://localhost:3000/greetings/hello (opens new window).