Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
More atrubyonrails.org:

Action Controller Overview

In this guide, you will learn how controllers work and how they fit into the request cycle in your application.

After reading this guide, you will know how to:

  • Follow the flow of a request through a controller.
  • Access parameters passed to your controller.
  • Use Strong Parameters and permit values.
  • Store data in the cookie, the session, and the flash.
  • Work with action callbacks to execute code during request processing.
  • Use the Request and Response Objects.

1. Introduction

Action Controller is the C in the Model View Controller(MVC)pattern. After therouter has matched a controller to anincoming request, the controller is responsible for processing the request andgenerating the appropriate output.

For most conventionalRESTfulapplications, the controller will receive the request, fetch or save data from amodel, and use a view to create HTML output.

You can imagine that a controller sits between models and views. The controllermakes model data available to the view, so that the view can display that datato the user. The controller also receives user input from the view and saves orupdates model data accordingly.

2. Creating a Controller

A controller is a Ruby class which inherits fromApplicationController and hasmethods just like any other class. Once an incoming request is matched to acontroller by the router, Rails creates an instance of that controller class andcalls the method with the same name as the action.

classClientsController<ApplicationControllerdefnewendend

Given the aboveClientsController, if a user goes to/clients/new in yourapplication to add a new client, Rails will create an instance ofClientsController and call itsnew method. If thenew method is empty, Railswill automatically render thenew.html.erb view by default.

Thenew method is an instance method here, called on an instance ofClientsController. This should not be confused with thenew class method (ieClientsController.new).

In thenew method, the controller would typically create an instance of theClient model, and make it available as an instance variable called@clientin the view:

defnew@client=Client.newend

All controllers inherit fromApplicationController, which in turninherits fromActionController::Base.ForAPI only applicationsApplicationController inherits fromActionController::API.

2.1. Controller Naming Convention

Rails favors making the resource in the controller's name plural. For example,ClientsController is preferred overClientController andSiteAdminsController overSiteAdminController orSitesAdminsController.However, the plural names are not strictly required (e.g.ApplicationController).

Following this naming convention will allow you to use thedefault routegenerators (e.g.resources) withoutneeding to qualify each with options such as:controller. The conventionalso makes named route helpers consistent throughout your application.

The controller naming convention is different from models. While plural namesare preferred for controller names, the singular form is preferred formodelnames (e.g.Account vs.Accounts).

Controller actions should bepublic, as onlypublic methods are callable asactions. It is also best practice to lower the visibility of helper methods(withprivate orprotected) which arenot intended to be actions.

Some method names are reserved by Action Controller. Accidentallyredefining them could result inSystemStackError. If you limit yourcontrollers to only RESTfulResource Routing actions you should not need toworry about this.

If you must use a reserved method as an action name, one workaround is touse a custom route to map the reserved method name to your non-reserved actionmethod.

3. Parameters

Data sent by the incoming request is available in your controller in theparams hash. There are two types of parameter data:

  • Query string parameters which are sent as part of the URL (for example, afterthe? inhttp://example.com/accounts?filter=free).
  • POST parameters which are submitted from an HTML form.

Rails does not make a distinction between query string parameters and POSTparameters; both are available in theparams hash in your controller. Forexample:

classClientsController<ApplicationController# This action receives query string parameters from an HTTP GET request# at the URL "/clients?status=activated"defindexifparams[:status]=="activated"@clients=Client.activatedelse@clients=Client.inactivatedendend# This action receives parameters from a POST request to "/clients" URL with  form data in the request body.defcreate@client=Client.new(params[:client])if@client.saveredirect_to@clientelserender"new"endendend

Theparams hash is not a plain old Ruby Hash; instead, it is anActionController::Parameters object. It does not inherit from Hash, but it behaves mostly like Hash.It provides methods for filteringparams and, unlike a Hash, keys:foo and"foo" are considered to be the same.

3.1. Hash and Array Parameters

Theparams hash is not limited to one-dimensional keys and values. It cancontain nested arrays and hashes. To send an array of values, append an emptypair of square brackets[] to the key name:

GET /users?ids[]=1&ids[]=2&ids[]=3

The actual URL in this example will be encoded as/users?ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3 as the[ and] characters arenot allowed in URLs. Most of the time you don't have to worry about this becausethe browser will encode it for you, and Rails will decode it automatically, butif you ever find yourself having to send those requests to the server manuallyyou should keep this in mind.

The value ofparams[:ids] will be the array["1", "2", "3"]. Note thatparameter values are always strings; Rails does not attempt to guess or cast thetype.

Values such as[nil] or[nil, nil, ...] inparams are replaced with[] for security reasons by default. SeeSecurityGuide for more information.

To send a hash, you include the key name inside the brackets:

<formaccept-charset="UTF-8"action="/users"method="post"><inputtype="text"name="user[name]"value="Acme"/><inputtype="text"name="user[phone]"value="12345"/><inputtype="text"name="user[address][postcode]"value="12345"/><inputtype="text"name="user[address][city]"value="Carrot City"/></form>

When this form is submitted, the value ofparams[:user] will be{ "name" =>"Acme", "phone" => "12345", "address" => { "postcode" => "12345", "city" =>"Carrot City" } }. Note the nested hash inparams[:user][:address].

Theparams object acts like a Hash, but lets you use symbols and stringsinterchangeably as keys.

3.2. Composite Key Parameters

Composite key parameters containmultiple values in one parameter separated by a delimiter (e.g., an underscore).Therefore, you will need to extract each value so that you can pass them toActive Record. You can use theextract_value method to do that.

For example, given the following controller:

classBooksController<ApplicationControllerdefshow# Extract the composite ID value from URL parameters.id=params.extract_value(:id)@book=Book.find(id)endend

And this route:

get"/books/:id",to:"books#show"

When a user requests the URL/books/4_2, the controller will extract thecomposite key value["4", "2"] and pass it toBook.find. Theextract_valuemethod may be used to extract arrays out of any delimited parameters.

3.3. JSON Parameters

If your application exposes an API, you will likely accept parameters in JSONformat. If thecontent-type header of your request is set toapplication/json, Rails will automatically load your parameters into theparams hash, which you can access as you would normally.

So for example, if you are sending this JSON content:

{"user":{"name":"acme","address":"123 Carrot Street"}}

Your controller will receive:

{"user"=>{"name"=>"acme","address"=>"123 Carrot Street"}}

3.3.1. Configuring Wrap Parameters

You can useWrap Parameters, which automatically add the controller name toJSON parameters. For example, you can send the below JSON without a root:userkey prefix:

{"name":"acme","address":"123 Carrot Street"}

Assuming that you're sending the above data to theUsersController, the JSONwill be wrapped within the:user key like this:

{name:"acme",address:"123 Carrot Street",user:{name:"acme",address:"123 Carrot Street"}}

Wrap Parameters adds a clone of the parameters to the hash within a keythat is the same as the controller name. As a result, both the original versionof the parameters and the "wrapped" version of the parameters will exist in theparams hash.

This feature clones and wraps parameters with a key chosen based on yourcontroller's name. It is configured totrue by default. If you do not want towrap parameters you canconfigureit tofalse.

config.action_controller.wrap_parameters_by_default=false

You can also customize the name of the key or specific parameters you want towrap, see theAPIdocumentationfor more.

3.4. Routing Parameters

Parameters specified as part of a route declaration in theroutes.rb file arealso made available in theparams hash. For example, we can add a route thatcaptures the:status parameter for a client:

get"/clients/:status",to:"clients#index",foo:"bar"

When a user navigates to/clients/active URL,params[:status] will be set to"active". When this route is used,params[:foo] will also be set to "bar", asif it were passed in the query string.

Any other parameters defined by the route declaration, such as:id, will alsobe available.

In the above example, your controller will also receiveparams[:action]as "index" andparams[:controller] as "clients". Theparams hash will alwayscontain the:controller and:action keys, but it's recommended to use themethodscontroller_name andaction_name instead to access thesevalues.

3.5. Thedefault_url_options Method

You can set global default parameters forurl_forby defining a method calleddefault_url_options in your controller. Forexample:

classApplicationController<ActionController::Basedefdefault_url_options{locale:I18n.locale}endend

The specified defaults will be used as a starting point when generating URLs.They can be overridden by the options passed tourl_for or any path helpersuch asposts_path. For example, by settinglocale: I18n.locale, Rails willautomatically add the locale to every URL:

posts_path# => "/posts?locale=en"

You can still override this default if needed:

posts_path(locale: :fr)# => "/posts?locale=fr"

Under the hood,posts_path is a shorthand for callingurl_for with theappropriate parameters.

If you definedefault_url_options inApplicationController, as in theexample above, these defaults will be used for all URL generation. The methodcan also be defined in a specific controller, in which case it only applies toURLs generated for that controller.

In a given request, the method is not actually called for every single generatedURL. For performance reasons the returned hash is cached per request.

4. Strong Parameters

With Action ControllerStrongParameters,parameters cannot be used in Active Model mass assignments until they have beenexplicitly permitted. This means you will need to decide which attributes topermit for mass update and declare them in the controller. This is a securitypractice to prevent users from accidentally updating sensitive model attributes.

In addition, parameters can be marked as required and the request will result ina 400 Bad Request being returned if not all required parameters are passed in.

classPeopleController<ActionController::Base# This will raise an ActiveModel::ForbiddenAttributesError# because it's using mass assignment without an explicit permit.defcreatePerson.create(params[:person])end# This will work as we are using `person_params` helper method, which has the# call to `expect` to allow mass assignment.defupdateperson=Person.find(params[:id])person.update!(person_params)redirect_topersonendprivate# Using a private method to encapsulate the permitted parameters is a good# pattern. You can use the same list for both create and update.defperson_paramsparams.expect(person:[:name,:age])endend

4.1. Permitting Values

4.1.1.expect

Theexpect method provides a concise and safe way to require and permitparameters.

id=params.expect(:id)

The aboveexpect will always return a scalar value and not an array or hash.Another example is form params, you can useexpect to ensure that the root keyis present and the attributes are permitted.

user_params=params.expect(user:[:username,:password])user_params.has_key?(:username)# => true

In the above example, if the:user key is not a nested hash with the specifiedkeys,expect will raise an error and return a 400 Bad Request response.

To require and permit an entire hash of parameters,expect can be used inthis way.

params.expect(log_entry:{})

This marks the:log_entry parameters hash and any sub-hash of it as permittedand does not check for permitted scalars, anything is accepted.

Extreme care should be taken when callingexpect with an emptyhash, as it will allow all current and future model attributes to bemass-assigned.

4.1.2.permit

Callingpermit allows the specified key inparams (:id or:adminbelow) for inclusion in mass assignment (e.g. viacreate orupdate):

params = ActionController::Parameters.new(id: 1, admin: "true")=>#<ActionController::Parameters{"id"=>1,"admin"=>"true"}permitted:false>params.permit(:id)=>#<ActionController::Parameters{"id"=>1}permitted:true>params.permit(:id,:admin)=>#<ActionController::Parameters{"id"=>1,"admin"=>"true"}permitted:true>

For the permitted key:id, its value also needs to be one of these permittedscalar values:String,Symbol,NilClass,Numeric,TrueClass,FalseClass,Date,Time,DateTime,StringIO,IO,ActionDispatch::Http::UploadedFile, andRack::Test::UploadedFile.

If you have not calledpermit on the key, it will be filtered out. Arrays,hashes, or any other objects are not injected by default.

To include a value inparams that's an array of one of the permitted scalarvalues, you can map the key to an empty array like this:

params = ActionController::Parameters.new(tags: ["rails", "parameters"])=>#<ActionController::Parameters{"tags"=>["rails","parameters"]}permitted:false>params.permit(tags:[])=>#<ActionController::Parameters{"tags"=>["rails","parameters"]}permitted:true>

To include hash values, you can map to an empty hash:

params = ActionController::Parameters.new(options: { darkmode: true })=>#<ActionController::Parameters{"options"=>{"darkmode"=>true}}permitted:false>params.permit(options:{})=>#<ActionController::Parameters{"options"=>#<ActionController::Parameters{"darkmode"=>true}permitted:true>}permitted:true>

The abovepermit call ensures that values inoptions are permitted scalarsand filters out anything else.

Thepermit with an empty hash is convenient since sometimes it is notpossible or convenient to declare each valid key of a hash parameter or itsinternal structure. But note that the abovepermit with an empty hash opensthe door to arbitrary input.

4.1.3.permit!

There is alsopermit! (with an!) which permits an entire hash ofparameters without checking the values.

params = ActionController::Parameters.new(id: 1, admin: "true")=>#<ActionController::Parameters{"id"=>1,"admin"=>"true"}permitted:false>params.permit!=>#<ActionController::Parameters{"id"=>1,"admin"=>"true"}permitted:true>

Extreme care should be taken when usingpermit!, as it will allow allcurrent andfuture model attributes to be mass-assigned.

4.2. Nested Parameters

You can also useexpect (orpermit) on nested parameters, like:

# Given the example expected params:params=ActionController::Parameters.new(name:"Martin",emails:["me@example.com"],friends:[{name:"André",family:{name:"RubyGems"},hobbies:["keyboards","card games"]},{name:"Kewe",family:{name:"Baroness"},hobbies:["video games"]},])# the following expect will ensure the params are permittedname,emails,friends=params.expect(:name,# permitted scalaremails:[],# array of permitted scalarsfriends:[[# array of permitted Parameter hashes:name,# permitted scalarfamily:[:name],# family: { name: "permitted scalar" }hobbies:[]# array of permitted scalars]])

This declaration permits thename,emails, andfriends attributes andreturns them each. It is expected thatemails will be an array of permittedscalar values, and thatfriends will be an array of resources (note the newdouble array syntax to explicitly require an array) with specific attributes.These attributes should have aname attribute (any permitted scalar values allowed), ahobbies attribute as an array of permitted scalar values, and afamilyattribute which is restricted to a hash with only aname key and any permittedscalar value.

4.3. Examples

Here are some examples of how to usepermit for different use cases.

Example 1: You may want to use the permitted attributes in yournew action.This raises the problem that you can't userequire on the root keybecause, normally, it does not exist when callingnew:

# using `fetch` you can supply a default and use# the Strong Parameters API from there.params.fetch(:blog,{}).permit(:title,:author)

Example 2: The model class methodaccepts_nested_attributes_for allows you toupdate and destroy associated records. This is based on theid and_destroyparameters:

# permit :id and :_destroyparams.expect(author:[:name,books_attributes:[[:title,:id,:_destroy]]])

Example 3: Hashes with integer keys are treated differently, and you can declarethe attributes as if they were direct children. You get these kinds ofparameters when you useaccepts_nested_attributes_for in combination with ahas_many association:

# To permit the following data:# {"book" => {"title" => "Some Book",#             "chapters_attributes" => { "1" => {"title" => "First Chapter"},#                                        "2" => {"title" => "Second Chapter"}}}}params.expect(book:[:title,chapters_attributes:[[:title]]])

Example 4: Imagine a scenario where you have parameters representing a productname, and a hash of arbitrary data associated with that product, and you want topermit the product name attribute and also the whole data hash:

defproduct_paramsparams.expect(product:[:name,data:{}])end

5. Cookies

The concept of a cookie is not specific to Rails. Acookie (also known as an HTTPcookie or a web cookie) is a small piece of data from the server that is savedin the user's browser. The browser may store cookies, create new cookies, modifyexisting ones, and send them back to the server with later requests. Cookiespersist data across web requests and therefore enable web applications toremember user preferences.

Rails provides an easy way to access cookies via thecookies method, whichworks like a hash:

classCommentsController<ApplicationControllerdefnew# Auto-fill the commenter's name if it has been stored in a cookie@comment=Comment.new(author:cookies[:commenter_name])enddefcreate@comment=Comment.new(comment_params)if@comment.saveifparams[:remember_name]# Save the commenter's name in a cookie.cookies[:commenter_name]=@comment.authorelse# Delete cookie for the commenter's name, if any.cookies.delete(:commenter_name)endredirect_to@comment.articleelserenderaction:"new"endendend

To delete a cookie, you need to usecookies.delete(:key). Setting thekey to anil value does not delete the cookie.

When passed a scalar value, the cookie will be deleted when the user closes their browser.If you want the cookie to expire at a specific time, pass a hash with the:expires option when setting the cookie.For example, to set a cookie that expires in 1 hour:

cookies[:login]={value:"XJ-122",expires:1.hour}

If you want to create cookies that never expire use the permanent cookie jar.This sets the assigned cookies to have an expiration date 20 years from now.

cookies.permanent[:locale]="fr"

5.1. Encrypted and Signed Cookies

Since cookies are stored on the client browser, they can be susceptible totampering and are not considered secure for storing sensitive data. Railsprovides a signed cookie jar and an encrypted cookie jar for storing sensitivedata. The signed cookie jar appends a cryptographic signature on the cookievalues to protect their integrity. The encrypted cookie jar encrypts the valuesin addition to signing them, so that they cannot be read by the user.

Refer to theAPIdocumentationfor more details.

classCookiesController<ApplicationControllerdefset_cookiecookies.signed[:user_id]=current_user.idcookies.encrypted[:expiration_date]=Date.tomorrow# => Thu, 20 Mar 2024redirect_toaction:"read_cookie"enddefread_cookiecookies.encrypted[:expiration_date]# => "2024-03-20"endend

These special cookie jars use a serializer to serialize the cookie values intostrings and deserialize them into Ruby objects when read back. You can specifywhich serializer to use viaconfig.action_dispatch.cookies_serializer. Thedefault serializer for new applications is:json.

Be aware that JSON has limited support serializing Ruby objects such asDate,Time, andSymbol. These will be serialized and deserialized intoStrings.

If you need to store these or more complex objects, you may need to manuallyconvert their values when reading them in subsequent requests.

If you use the cookie session store, the above applies to thesession andflash hash as well.

6. Session

While cookies are stored client-side, session data is stored server-side (inmemory, a database, or a cache), and the duration is usually temporary and tiedto the user's session (e.g. until they close the browser). An example use casefor session is storing sensitive data like user authentication.

In a Rails application, the session is available in the controller and the view.

6.1. Working with the Session

You can use thesession instance method to access the session in yourcontrollers. Session values are stored as key/value pairs like a hash:

classApplicationController<ActionController::Baseprivate# Look up the key `:current_user_id` in the session and use it to# find the current `User`. This is a common way to handle user login in# a Rails application; logging in sets the session value and# logging out removes it.defcurrent_user@current_user||=User.find_by(id:session[:current_user_id])ifsession[:current_user_id]endend

To store something in the session, you can assign it to a key similar to addinga value to a hash. After a user is authenticated, itsid is saved in thesession to be used for subsequent requests:

classSessionsController<ApplicationControllerdefcreateifuser=User.authenticate_by(email:params[:email],password:params[:password])# Save the user ID in the session so it can be used in# subsequent requestssession[:current_user_id]=user.idredirect_toroot_urlendendend

To remove something from the session, delete the key/value pair. Deleting thecurrent_user_id key from the session is a typical way to log the user out:

classSessionsController<ApplicationControllerdefdestroysession.delete(:current_user_id)# Clear the current user as well.@current_user=nilredirect_toroot_url,status: :see_otherendend

It is possible to reset the entire session withreset_session. It isrecommended to usereset_session after logging in to avoid session fixationattacks. Please refer to theSecurityGuidefor details.

Sessions are lazily loaded. If you don't access sessions in your action'scode, they will not be loaded. Hence, you will never need to disable sessions -not accessing them will do the job.

6.2. The Flash

Theflashprovides a way to pass temporary data between controller actions. Anything youplace in the flash will be available to the very next action and then cleared.The flash is typically used for setting messages (e.g. notices and alerts) in acontroller action before redirecting to an action that displays the message tothe user.

The flash is accessed via theflash method. Similar to the session, theflash values are stored as key/value pairs.

For example, in the controller action for logging out a user, the controller canset a flash message which can be displayed to the user on the next request:

classSessionsController<ApplicationControllerdefdestroysession.delete(:current_user_id)flash[:notice]="You have successfully logged out."redirect_toroot_url,status: :see_otherendend

Displaying a message after a user performs some interactive action in yourapplication is a good practice to give the user feedback that their action wassuccessful (or that there were errors).

In addition to:notice, you can also use:alert. These are typically styled(using CSS) with different colors to indicate their meaning (e.g. green fornotices and orange/red for alerts).

You can also assign a flash message directly within theredirect_to method byincluding it as a parameter toredirect_to:

redirect_toroot_url,notice:"You have successfully logged out."redirect_toroot_url,alert:"There was an issue."

You're not limited tonotice andalert.You can set any key in a flash (similar to sessions), by assigning it to the:flash argument.For example, assigning:just_signed_up:

redirect_toroot_url,flash:{just_signed_up:true}

This will allow you to have the below in the view:

<%ifflash[:just_signed_up]%><pclass="welcome">Welcome to our site!</p><%end%>

In the above logout example, thedestroy action redirects to the application'sroot_url, where the message is available to be displayed. However, it's notdisplayed automatically. It's up to the next action to decide what, if anything,it will do with what the previous action put in the flash.

6.2.1. Displaying flash messages

If a previous actionhas set a flash message, it's a good idea to display thatto the user. We can accomplish this consistently by adding the HTML fordisplaying any flash messages in the application's default layout. Here's anexample fromapp/views/layouts/application.html.erb:

<html><!-- <head/> --><body><%flash.eachdo|name,msg|-%><%=content_tag:div,msg,class:name%><%end-%><!-- more content --><%=yield%></body></html>

Thename above indicates the type of flash message, such asnotice oralert. This information is normally used to style how the message is displayedto the user.

You can filter byname if you want to limit to displaying onlynoticeandalert in layout. Otherwise, all keys set in theflash will be displayed.

Including the reading and displaying of flash messages in the layout ensuresthat your application will display these automatically, without each view havingto include logic to read the flash.

6.2.2.flash.keep andflash.now

flash.keep is used to carry over the flash value through to an additionalrequest. This is useful when there are multiple redirects.

For example, assume that theindex action in the controller below correspondsto theroot_url. And you want all requests here to be redirected toUsersController#index. If an action sets the flash and redirects toMainController#index, those flash values will be lost when another redirecthappens, unless you useflash.keep to make the values persist for anotherrequest.

classMainController<ApplicationControllerdefindex# Will persist all flash values.flash.keep# You can also use a key to keep only some kind of value.# flash.keep(:notice)redirect_tousers_urlendend

flash.now is used to make the flash values available in the same request.By default, adding values to the flash will make them available to the nextrequest. For example, if thecreate action fails to save a resource, and yourender thenew template directly, that's not going to result in a new request,but you may still want to display a message using the flash. To do this, you canuseflash.now in the same way you use the normalflash:

classClientsController<ApplicationControllerdefcreate@client=Client.new(client_params)if@client.save# ...elseflash.now[:error]="Could not save client"renderaction:"new"endendend

6.3. Session Stores

All sessions have a unique ID that represents the session object; these sessionIDs are stored in a cookie. The actual session objects use one of the followingstorage mechanisms:

For most session stores, the unique session ID in the cookie is used to look upsession data on the server (e.g. a database table). Rails does not allow you topass the session ID in the URL as this is less secure.

6.3.1.CookieStore

TheCookieStore is the default and recommended session store. It stores allsession data in the cookie itself (the session ID is still available to you ifyou need it). TheCookieStore is lightweight and does not require anyconfiguration to use in a new application.

TheCookieStore can store 4 kB of data - much less than the other storageoptions - but this is usually enough. Storing large amounts of data in thesession is discouraged. You should especially avoid storing complex objects(such as model instances) in the session.

6.3.2.CacheStore

You can use theCacheStore if your sessions don't store critical data or don'tneed to be around for long periods (for instance if you just use the flash formessaging). This will store sessions using the cache implementation you haveconfigured for your application. The advantage is that you can use your existingcache infrastructure for storing sessions without requiring any additional setupor administration. The downside is that the session storage will be temporaryand they could disappear at any time.

Read more about session storage in theSecurity Guide.

6.4. Session Storage Options

There are a few configuration options related to session storage. You canconfigure the type of storage in an initializer:

Rails.application.config.session_store:cache_store

Rails sets up a session key (the name of the cookie) when signing the sessiondata. These can also be changed in an initializer:

Rails.application.config.session_store:cookie_store,key:"_your_app_session"

Be sure to restart your server when you modify an initializer file.

You can also pass a:domain key and specify the domain name for the cookie:

Rails.application.config.session_store:cookie_store,key:"_your_app_session",domain:".example.com"

Seeconfig.session_store in theconfiguration guide for more information.

Rails sets up a secret key forCookieStore used for signing the session datainconfig/credentials.yml.enc. The credentials can be updated withbin/railscredentials:edit.

# aws:#   access_key_id: 123#   secret_access_key: 345# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.secret_key_base:492f...

Changing thesecret_key_base when using theCookieStore willinvalidate all existing sessions. You'll need to configure acookie rotatorto rotate existing sessions.

7. Controller Callbacks

Controller callbacks are methods that are defined to automatically run beforeand/or after a controller action. A controller callback method can be defined ina given controller or in theApplicationController. Since all controllersinherit fromApplicationController, callbacks defined here will run on everycontroller in your application.

7.1.before_action

Callback methods registered viabefore_action runbefore a controlleraction. They may halt the request cycle. A common use case forbefore_actionis ensuring that a user is logged in:

classApplicationController<ActionController::Basebefore_action:require_loginprivatedefrequire_loginunlesslogged_in?flash[:error]="You must be logged in to access this section"redirect_tonew_login_url# halts request cycleendendend

The method stores an error message in the flash and redirects to the login formif the user is not already logged in. When abefore_action callback renders orredirects (like in the example above), the original controller action is notrun. If there are additional callbacks registered to run, they are alsocancelled and not run.

In this example, thebefore_action is defined inApplicationController soall controllers in the application inherit it. That implies that all requests inthe application will require the user to be logged in. This is fine except forthe "login" page. The "login" action should succeed even when the user is notlogged in (to allow the user to log in) otherwise the user will never be able tolog in. You can useskip_before_action to allow specified controlleractions to skip a givenbefore_action:

classLoginsController<ApplicationControllerskip_before_action:require_login,only:[:new,:create]end

Now, theLoginsController'snew andcreate actions will work withoutrequiring the user to be logged in.

The:only option skips the callback only for the listed actions; there is alsoan:except option which works the other way. These options can be used whenregistering action callbacks too, to add callbacks which only run for selectedactions.

If you register the same action callback multiple times with differentoptions, the last action callback definition will overwrite the previous ones.

7.2.after_action andaround_action

You can also define action callbacks to runafter a controller action has beenexecuted withafter_action, or to run both before and after witharound_action.

Theafter_action callbacks are similar tobefore_action callbacks, butbecause the controller action has already been run they have access to theresponse data that's about to be sent to the client.

after_action callbacks are executed only after a successful controlleraction, and not if an exception is raised in the request cycle.

Thearound_action callbacks are useful when you want to execute code beforeand after a controller action, allowing you to encapsulate functionality thataffects the action's execution. They are responsible for running theirassociated actions by yielding.

For example, imagine you want to monitor the performance of specific actions.You could use anaround_action to measure how long each action takes tocomplete and log this information:

classApplicationController<ActionController::Basearound_action:measure_execution_timeprivatedefmeasure_execution_timestart_time=Time.nowyield# This executes the actionend_time=Time.nowduration=end_time-start_timeRails.logger.info"Action#{action_name} from controller#{controller_name} took#{duration.round(2)} seconds to execute."endend

Action callbacks receivecontroller_name andaction_name as parametersyou can use, as shown in the example above.

Thearound_action callback also wraps rendering. In the example above, viewrendering will be included in theduration. The code after theyield in anaround_action is run even when there is an exception in the associated actionand there is anensure block in the callback. (This is different fromafter_action callbacks where an exception in the action cancels theafter_action code.)

7.3. Other Ways to Use Callbacks

In addition tobefore_action,after_action, oraround_action, there aretwo less common ways to register callbacks.

The first is to use a block directly with the*_action methods. The blockreceives the controller as an argument. For example, therequire_login actioncallback from above could be rewritten to use a block:

classApplicationController<ActionController::Basebefore_actiondo|controller|unlesscontroller.send(:logged_in?)flash[:error]="You must be logged in to access this section"redirect_tonew_login_urlendendend

Note that the action callback, in this case, usessend because thelogged_in? method is private, and the action callback does not run in thescope of the controller. This is not the recommended way to implement thisparticular action callback, but in simpler cases, it might be useful.

Specifically foraround_action, the block also yields in theaction:

around_action{|_controller,action|time(&action)}

The second way is to specify a class (or any object that responds to theexpected methods) for the callback action. This can be useful in cases that aremore complex. As an example, you could rewrite thearound_action callback tomeasure execution time with a class:

classApplicationController<ActionController::Basearound_actionActionDurationCallbackendclassActionDurationCallbackdefself.around(controller)start_time=Time.nowyield# This executes the actionend_time=Time.nowduration=end_time-start_timeRails.logger.info"Action#{controller.action_name} from controller#{controller.controller_name} took#{duration.round(2)} seconds to execute."endend

In above example, theActionDurationCallback's method is not run in the scopeof the controller but getscontroller as an argument.

In general, the class being used for a*_action callback must implement amethod with the same name as the action callback. So for thebefore_actioncallback, the class must implement abefore method, and so on. Also,thearound method mustyield to execute the action.

8. The Request and Response Objects

Every controller has two methods,request andresponse, which can beused to access the request and response objects associated with thecurrent request cycle. Therequest method returns an instance ofActionDispatch::Request. Theresponse method returns an an instanceofActionDispatch::Response, an object representing what is going to besent back to the client browser (e.g. fromrender orredirect in thecontroller action).

8.1. Therequest Object

The request object contains useful information about the request coming in fromthe client. This section describes the purpose of some of the properties of therequest object.

To get a full list of the available methods, refer to theRails APIdocumentationandRackdocumentation.

Property ofrequestPurpose
hostThe hostname used for this request.
domain(n=2)The hostname's firstn segments, starting from the right (the TLD).
formatThe content type requested by the client.
methodThe HTTP method used for the request.
get?,post?,patch?,put?,delete?,head?Returns true if the HTTP method is GET/POST/PATCH/PUT/DELETE/HEAD.
headersReturns a hash containing the headers associated with the request.
portThe port number (integer) used for the request.
protocolReturns a string containing the protocol used plus "://", for example "http://".
query_stringThe query string part of the URL, i.e., everything after "?".
remote_ipThe IP address of the client.
urlThe entire URL used for the request.

8.1.1.query_parameters,request_parameters, andpath_parameters

Rails collects all of the parameters for a given request in theparams hash,including the ones set in the URL as query string parameters, and those sent asthe body of aPOST request. The request object has three methods that give youaccess to the various parameters.

  • query_parameters - contains parameters that were sent as part of thequery string.
  • request_parameters - contains parameters sent as part of the post body.
  • path_parameters - contains parameters parsed by the router as being partof the path leading to this particular controller and action.

8.2. Theresponse Object

The response object is built up during the execution of the action fromrendering data to be sent back to the client browser. It's not usually useddirectly but sometimes, in anafter_action callback for example, it can beuseful to access the response directly. One use case is for setting the content type header:

response.content_type="application/pdf"

Another use case is for setting custom response headers:

response.headers["X-Custom-Header"]="some value"

Theheaders attribute is a hash which maps header names to header values.Rails sets some headers automatically but if you need to update a header or adda custom header, you can useresponse.headers as in the example above.

Theheaders method can be accessed directly in the controller as well.

Here are some of the properties of theresponse object:

Property ofresponsePurpose
bodyThis is the string of data being sent back to the client. This is most often HTML.
statusThe HTTP status code for the response, like 200 for a successful request or 404 for file not found.
locationThe URL the client is being redirected to, if any.
content_typeThe content type of the response.
charsetThe character set being used for the response. Default is "utf-8".
headersHeaders used for the response.

To get a full list of the available methods, refer to theRails APIdocumentationandRackDocumentation.



Back to top
[8]ページ先頭

©2009-2025 Movatter.jp