Link to API docs in Action Controller guide [ci-skip]

This links the first mention of each method to its API documentation,
similar to a Wikipedia article.  Some subsequent mentions are also
linked, when it suits the surrounding text.

This also modifies the text in a few places to ensure that methods are
explicitly mentioned (and linked) before they appear in code examples.
This commit is contained in:
Jonathan Hefner 2020-11-08 21:07:47 -06:00
parent bcb63fcaa8
commit 5dc3955faf
1 changed files with 84 additions and 29 deletions

View File

@ -61,14 +61,16 @@ end
The [Layouts & Rendering Guide](layouts_and_rendering.html) explains this in more detail.
`ApplicationController` inherits from `ActionController::Base`, which defines a number of helpful methods. This guide will cover some of these, but if you're curious to see what's in there, you can see all of them in the [API documentation](https://api.rubyonrails.org/classes/ActionController.html) or in the source itself.
`ApplicationController` inherits from [`ActionController::Base`][], which defines a number of helpful methods. This guide will cover some of these, but if you're curious to see what's in there, you can see all of them in the [API documentation](https://api.rubyonrails.org/classes/ActionController.html) or in the source itself.
Only public methods are callable as actions. It is a best practice to lower the visibility of methods (with `private` or `protected`) which are not intended to be actions, like auxiliary methods or filters.
[`ActionController::Base`]: https://api.rubyonrails.org/classes/ActionController/Base.html
Parameters
----------
You will probably want to access data sent in by the user or other parameters in your controller actions. There are two kinds of parameters possible in a web application. The first are parameters that are sent as part of the URL, called query string parameters. The query string is everything after "?" in the URL. The second type of parameter is usually referred to as POST data. This information usually comes from an HTML form which has been filled in by the user. It's called POST data because it can only be sent as part of an HTTP POST request. Rails does not make any distinction between query string parameters and POST parameters, and both are available in the `params` hash in your controller:
You will probably want to access data sent in by the user or other parameters in your controller actions. There are two kinds of parameters possible in a web application. The first are parameters that are sent as part of the URL, called query string parameters. The query string is everything after "?" in the URL. The second type of parameter is usually referred to as POST data. This information usually comes from an HTML form which has been filled in by the user. It's called POST data because it can only be sent as part of an HTTP POST request. Rails does not make any distinction between query string parameters and POST parameters, and both are available in the [`params`][] hash in your controller:
```ruby
class ClientsController < ApplicationController
@ -102,6 +104,8 @@ class ClientsController < ApplicationController
end
```
[`params`]: https://api.rubyonrails.org/classes/ActionController/StrongParameters.html#method-i-params
### Hash and Array Parameters
The `params` hash is not limited to one-dimensional keys and values. It can contain nested arrays and hashes. To send an array of values, append an empty pair of square brackets "[]" to the key name:
@ -145,7 +149,7 @@ So for example, if you are sending this JSON content:
Your controller will receive `params[:company]` as `{ "name" => "acme", "address" => "123 Carrot Street" }`.
Also, if you've turned on `config.wrap_parameters` in your initializer or called `wrap_parameters` in your controller, you can safely omit the root element in the JSON parameter. In this case, the parameters will be cloned and wrapped with a key chosen based on your controller's name. So the above JSON request can be written as:
Also, if you've turned on `config.wrap_parameters` in your initializer or called [`wrap_parameters`][] in your controller, you can safely omit the root element in the JSON parameter. In this case, the parameters will be cloned and wrapped with a key chosen based on your controller's name. So the above JSON request can be written as:
```json
{ "name": "acme", "address": "123 Carrot Street" }
@ -161,9 +165,11 @@ You can customize the name of the key or specific parameters you want to wrap by
NOTE: Support for parsing XML parameters has been extracted into a gem named `actionpack-xml_parser`.
[`wrap_parameters`]: https://api.rubyonrails.org/classes/ActionController/ParamsWrapper/Options/ClassMethods.html#method-i-wrap_parameters
### Routing Parameters
The `params` hash will always contain the `:controller` and `:action` keys, but you should use the methods `controller_name` and `action_name` instead to access these values. Any other parameters defined by the routing, such as `:id`, will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the `:status` parameter in a "pretty" URL:
The `params` hash will always contain the `:controller` and `:action` keys, but you should use the methods [`controller_name`][] and [`action_name`][] instead to access these values. Any other parameters defined by the routing, such as `:id`, will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the `:status` parameter in a "pretty" URL:
```ruby
get '/clients/:status', to: 'clients#index', foo: 'bar'
@ -171,6 +177,9 @@ get '/clients/:status', to: 'clients#index', foo: 'bar'
In this case, when a user opens the URL `/clients/active`, `params[:status]` will be set to "active". When this route is used, `params[:foo]` will also be set to "bar", as if it were passed in the query string. Your controller will also receive `params[:action]` as "index" and `params[:controller]` as "clients".
[`controller_name`]: https://api.rubyonrails.org/classes/ActionController/Metal.html#method-i-controller_name
[`action_name`]: https://api.rubyonrails.org/classes/AbstractController/Base.html#method-i-action_name
### `default_url_options`
You can set global default parameters for URL generation by defining a method called `default_url_options` in your controller. Such a method must return a hash with the desired defaults, whose keys must be symbols:
@ -235,13 +244,13 @@ end
#### Permitted Scalar Values
Given
Calling [`permit`][] like:
```ruby
params.permit(:id)
```
the key `:id` will be permitted for inclusion if it appears in `params` and
permits the specified key (`:id`) for inclusion if it appears in `params` and
it has a permitted scalar value associated. Otherwise, the key is going
to be filtered out, so arrays, hashes, or any other objects cannot be
injected.
@ -269,7 +278,7 @@ but be careful because this opens the door to arbitrary input. In this
case, `permit` ensures values in the returned structure are permitted
scalars and filters out anything else.
To permit an entire hash of parameters, the `permit!` method can be
To permit an entire hash of parameters, the [`permit!`][] method can be
used:
```ruby
@ -281,6 +290,9 @@ permitted and does not check for permitted scalars, anything is accepted.
Extreme care should be taken when using `permit!`, as it will allow all current
and future model attributes to be mass-assigned.
[`permit`]: https://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit
[`permit!`]: https://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit-21
#### Nested Parameters
You can also use `permit` on nested parameters, like:
@ -302,7 +314,7 @@ to having a `name` (any permitted scalar values allowed here, too).
#### More Examples
You may want to also use the permitted attributes in your `new`
action. This raises the problem that you can't use `require` on the
action. This raises the problem that you can't use [`require`][] on the
root key because, normally, it does not exist when calling `new`:
```ruby
@ -345,6 +357,8 @@ def product_params
end
```
[`require`]: https://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-require
#### Outside the Scope of Strong Parameters
The strong parameter API was designed with the most common use cases
@ -357,10 +371,10 @@ Session
Your application has a session for each user in which you can store small amounts of data that will be persisted between requests. The session is only available in the controller and the view and can use one of a number of different storage mechanisms:
* `ActionDispatch::Session::CookieStore` - Stores everything on the client.
* `ActionDispatch::Session::CacheStore` - Stores the data in the Rails cache.
* [`ActionDispatch::Session::CookieStore`][] - Stores everything on the client.
* [`ActionDispatch::Session::CacheStore`][] - Stores the data in the Rails cache.
* `ActionDispatch::Session::ActiveRecordStore` - Stores the data in a database using Active Record. (require `activerecord-session_store` gem).
* `ActionDispatch::Session::MemCacheStore` - Stores the data in a memcached cluster (this is a legacy implementation; consider using CacheStore instead).
* [`ActionDispatch::Session::MemCacheStore`][] - Stores the data in a memcached cluster (this is a legacy implementation; consider using CacheStore instead).
All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
@ -408,6 +422,10 @@ secret_key_base: 492f...
NOTE: Changing the secret_key_base when using the `CookieStore` will invalidate all existing sessions.
[`ActionDispatch::Session::CookieStore`]: https://api.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html
[`ActionDispatch::Session::CacheStore`]: https://api.rubyonrails.org/classes/ActionDispatch/Session/CacheStore.html
[`ActionDispatch::Session::MemCacheStore`]: https://api.rubyonrails.org/classes/ActionDispatch/Session/MemCacheStore.html
### Accessing the Session
In your controller you can access the session through the `session` instance method.
@ -463,13 +481,15 @@ class LoginsController < ApplicationController
end
```
To reset the entire session, use `reset_session`.
To reset the entire session, use [`reset_session`][].
[`reset_session`]: https://api.rubyonrails.org/classes/ActionController/Metal.html#method-i-reset_session
### The Flash
The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for passing error messages etc.
It is accessed in much the same way as the session, as a hash (it's a [FlashHash](https://api.rubyonrails.org/classes/ActionDispatch/Flash/FlashHash.html) instance).
The flash is accessed via the [`flash`][] method. Like the session, the flash is represented as a hash.
Let's use the act of logging out as an example. The controller can send a message which will be displayed to the user on the next request:
@ -516,7 +536,7 @@ You can pass anything that the session can store; you're not limited to notices
<% end %>
```
If you want a flash value to be carried over to another request, use the `keep` method:
If you want a flash value to be carried over to another request, use [`flash.keep`][]:
```ruby
class MainController < ApplicationController
@ -536,9 +556,12 @@ class MainController < ApplicationController
end
```
[`flash`]: https://api.rubyonrails.org/classes/ActionDispatch/Flash/RequestMethods.html#method-i-flash
[`flash.keep`]: https://api.rubyonrails.org/classes/ActionDispatch/Flash/FlashHash.html#method-i-keep
#### `flash.now`
By default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request. For example, if the `create` action fails to save a resource and you render the `new` 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 can use `flash.now` in the same way you use the normal `flash`:
By default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request. For example, if the `create` action fails to save a resource and you render the `new` 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 can use [`flash.now`][] in the same way you use the normal `flash`:
```ruby
class ClientsController < ApplicationController
@ -554,10 +577,12 @@ class ClientsController < ApplicationController
end
```
[`flash.now`]: https://api.rubyonrails.org/classes/ActionDispatch/Flash/FlashHash.html#method-i-now
Cookies
-------
Your application can store small amounts of data on the client - called cookies - that will be persisted across requests and even sessions. Rails provides easy access to cookies via the `cookies` method, which - much like the `session` - works like a hash:
Your application can store small amounts of data on the client - called cookies - that will be persisted across requests and even sessions. Rails provides easy access to cookies via the [`cookies`][] method, which - much like the `session` - works like a hash:
```ruby
class CommentsController < ApplicationController
@ -643,6 +668,8 @@ manually when reading the values on subsequent requests.
If you use the cookie session store, this would apply to the `session` and
`flash` hash as well.
[`cookies`]: https://api.rubyonrails.org/classes/ActionController/Cookies.html#method-i-cookies
Rendering XML and JSON data
---------------------------
@ -670,7 +697,7 @@ Filters are methods that are run "before", "after" or "around" a controller acti
Filters are inherited, so if you set a filter on `ApplicationController`, it will be run on every controller in your application.
"before" filters 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:
"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:
```ruby
class ApplicationController < ActionController::Base
@ -689,7 +716,7 @@ end
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 in order 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`:
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 in order 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`][]:
```ruby
class LoginsController < ApplicationController
@ -702,13 +729,16 @@ Now, the `LoginsController`'s `new` and `create` actions will work as before wit
NOTE: Calling the same filter multiple times with different options will not work,
since the last filter definition will overwrite the previous ones.
[`before_action`]: https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-before_action
[`skip_before_action`]: https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-skip_before_action
### 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 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.
"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 responsible for running their associated actions by yielding, similar to how Rack middlewares work.
"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:
@ -734,6 +764,9 @@ Note that an "around" filter also wraps rendering. In particular, in the example
You can choose not to yield and build the response yourself, in which case the action will not be run.
[`after_action`]: https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-after_action
[`around_action`]: https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-around_action
### Other Ways to Use Filters
While the most common way to use filters is by creating private methods and using *_action to add them, there are two other ways to do the same thing.
@ -816,7 +849,11 @@ The [Security Guide](security.html) has more about this and a lot of other secur
The Request and Response Objects
--------------------------------
In every controller there are two accessor methods pointing to the request and the response objects associated with the request cycle that is currently in execution. The `request` method contains an instance of `ActionDispatch::Request` and the `response` method returns a response object representing what is going to be sent back to the client.
In every controller there are two accessor methods pointing to the request and the response objects associated with the request cycle that is currently in execution. The [`request`][] method contains an instance of [`ActionDispatch::Request`][] and the [`response`][] method returns a response object representing what is going to be sent back to the client.
[`ActionDispatch::Request`]: https://api.rubyonrails.org/classes/ActionDispatch/Request.html
[`request`]: https://api.rubyonrails.org/classes/ActionController/Base.html#method-i-request
[`response`]: https://api.rubyonrails.org/classes/ActionController/Base.html#method-i-response
### The `request` Object
@ -838,7 +875,11 @@ The request object contains a lot of useful information about the request coming
#### `path_parameters`, `query_parameters`, and `request_parameters`
Rails collects all of the parameters sent along with the request in the `params` hash, whether they are sent as part of the query string or the post body. The request object has three accessors that give you access to these parameters depending on where they came from. The `query_parameters` hash contains parameters that were sent as part of the query string while the `request_parameters` hash contains parameters sent as part of the post body. The `path_parameters` hash contains parameters that were recognized by the routing as being part of the path leading to this particular controller and action.
Rails collects all of the parameters sent along with the request in the `params` hash, whether they are sent as part of the query string or the post body. The request object has three accessors that give you access to these parameters depending on where they came from. The [`query_parameters`][] hash contains parameters that were sent as part of the query string while the [`request_parameters`][] hash contains parameters sent as part of the post body. The [`path_parameters`][] hash contains parameters that were recognized by the routing as being part of the path leading to this particular controller and action.
[`path_parameters`]: https://api.rubyonrails.org/classes/ActionDispatch/Http/Parameters.html#method-i-path_parameters
[`query_parameters`]: https://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-query_parameters
[`request_parameters`]: https://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-request_parameters
### The `response` Object
@ -874,7 +915,7 @@ Rails comes with three built-in HTTP authentication mechanisms:
### HTTP Basic Authentication
HTTP basic authentication is an authentication scheme that is supported by the majority of browsers and other HTTP clients. As an example, consider an administration section which will only be available by entering a username and a password into the browser's HTTP basic dialog window. Using the built-in authentication is quite easy and only requires you to use one method, `http_basic_authenticate_with`.
HTTP basic authentication is an authentication scheme that is supported by the majority of browsers and other HTTP clients. As an example, consider an administration section which will only be available by entering a username and a password into the browser's HTTP basic dialog window. Using the built-in authentication is quite easy and only requires you to use one method, [`http_basic_authenticate_with`][].
```ruby
class AdminsController < ApplicationController
@ -884,9 +925,11 @@ end
With this in place, you can create namespaced controllers that inherit from `AdminsController`. The filter will thus be run for all actions in those controllers, protecting them with HTTP basic authentication.
[`http_basic_authenticate_with`]: https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic/ControllerMethods/ClassMethods.html#method-i-http_basic_authenticate_with
### HTTP Digest Authentication
HTTP digest authentication is superior to the basic authentication as it does not require the client to send an unencrypted password over the network (though HTTP basic authentication is safe over HTTPS). Using digest authentication with Rails is quite easy and only requires using one method, `authenticate_or_request_with_http_digest`.
HTTP digest authentication is superior to the basic authentication as it does not require the client to send an unencrypted password over the network (though HTTP basic authentication is safe over HTTPS). Using digest authentication with Rails is quite easy and only requires using one method, [`authenticate_or_request_with_http_digest`][].
```ruby
class AdminsController < ApplicationController
@ -905,11 +948,13 @@ end
As seen in the example above, the `authenticate_or_request_with_http_digest` block takes only one argument - the username. And the block returns the password. Returning `false` or `nil` from the `authenticate_or_request_with_http_digest` will cause authentication failure.
[`authenticate_or_request_with_http_digest`]: https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Digest/ControllerMethods.html#method-i-authenticate_or_request_with_http_digest
### HTTP Token Authentication
HTTP token authentication is a scheme to enable the usage of Bearer tokens in the HTTP `Authorization` header. There are many token formats available and describing them is outside the scope of this document.
As an example, suppose you want to use an authentication token that has been issued in advance to perform authentication and access. Implementing token authentication with Rails is quite easy and only requires using one method, `authenticate_or_request_with_http_token`.
As an example, suppose you want to use an authentication token that has been issued in advance to perform authentication and access. Implementing token authentication with Rails is quite easy and only requires using one method, [`authenticate_or_request_with_http_token`][].
```ruby
class PostsController < ApplicationController
@ -928,10 +973,12 @@ end
As seen in the example above, the `authenticate_or_request_with_http_token` block takes two arguments - the token and a `Hash` containing the options that were parsed from the HTTP `Authorization` header. The block should return `true` if the authentication is successful. Returning `false` or `nil` on it will cause an authentication failure.
[`authenticate_or_request_with_http_token`]: https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token/ControllerMethods.html#method-i-authenticate_or_request_with_http_token
Streaming and File Downloads
----------------------------
Sometimes you may want to send a file to the user instead of rendering an HTML page. All controllers in Rails have the `send_data` and the `send_file` methods, which will both stream data to the client. `send_file` is a convenience method that lets you provide the name of a file on the disk and it will stream the contents of that file for you.
Sometimes you may want to send a file to the user instead of rendering an HTML page. All controllers in Rails have the [`send_data`][] and the [`send_file`][] methods, which will both stream data to the client. `send_file` is a convenience method that lets you provide the name of a file on the disk and it will stream the contents of that file for you.
To stream data to the client, use `send_data`:
@ -960,6 +1007,9 @@ end
The `download_pdf` action in the example above will call a private method which actually generates the PDF document and returns it as a string. This string will then be streamed to the client as a file download and a filename will be suggested to the user. Sometimes when streaming files to the user, you may not want them to download the file. Take images, for example, which can be embedded into HTML pages. To tell the browser a file is not meant to be downloaded, you can set the `:disposition` option to "inline". The opposite and default value for this option is "attachment".
[`send_data`]: https://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data
[`send_file`]: https://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_file
### Sending Files
If you want to send a file that already exists on disk, use the `send_file` method.
@ -1019,10 +1069,11 @@ GET /clients/1.pdf
### Live Streaming of Arbitrary Data
Rails allows you to stream more than just files. In fact, you can stream anything
you would like in a response object. The `ActionController::Live` module allows
you would like in a response object. The [`ActionController::Live`][] module allows
you to create a persistent connection with a browser. Using this module, you will
be able to send arbitrary data to the browser at specific points in time.
[`ActionController::Live`]: https://api.rubyonrails.org/classes/ActionController/Live.html
#### Incorporating Live Streaming
@ -1148,7 +1199,7 @@ By default, in the production environment the application will render either a 4
### `rescue_from`
If you want to do something a bit more elaborate when catching errors, you can use `rescue_from`, which handles exceptions of a certain type (or multiple types) in an entire controller and its subclasses.
If you want to do something a bit more elaborate when catching errors, you can use [`rescue_from`][], which handles exceptions of a certain type (or multiple types) in an entire controller and its subclasses.
When an exception occurs which is caught by a `rescue_from` directive, the exception object is passed to the handler. The handler can be a method or a `Proc` object passed to the `:with` option. You can also use a block directly instead of an explicit `Proc` object.
@ -1203,9 +1254,13 @@ a custom behavior you don't need to handle this.
NOTE: Certain exceptions are only rescuable from the `ApplicationController` class, as they are raised before the controller gets initialized and the action gets executed.
[`rescue_from`]: https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html#method-i-rescue_from
Force HTTPS protocol
--------------------
If you'd like to ensure that communication to your controller is only possible
via HTTPS, you should do so by enabling the `ActionDispatch::SSL` middleware via
via HTTPS, you should do so by enabling the [`ActionDispatch::SSL`][] middleware via
`config.force_ssl` in your environment configuration.
[`ActionDispatch::SSL`]: https://api.rubyonrails.org/classes/ActionDispatch/SSL.html