# frozen_string_literal: true
# :markup: markdown
require "action_view"
require "action_controller/log_subscriber"
require "action_controller/metal/params_wrapper"
module ActionController
# # Action Controller Base
#
# Action Controllers are the core of a web request in Rails. They are made up of
# one or more actions that are executed on request and then either it renders a
# template or redirects to another action. An action is defined as a public
# method on the controller, which will automatically be made accessible to the
# web-server through Rails Routes.
#
# By default, only the ApplicationController in a Rails application inherits
# from `ActionController::Base`. All other controllers inherit from
# ApplicationController. This gives you one class to configure things such as
# request forgery protection and filtering of sensitive request parameters.
#
# A sample controller could look like this:
#
# class PostsController < ApplicationController
# def index
# @posts = Post.all
# end
#
# def create
# @post = Post.create params[:post]
# redirect_to posts_path
# end
# end
#
# Actions, by default, render a template in the `app/views` directory
# corresponding to the name of the controller and action after executing code in
# the action. For example, the `index` action of the PostsController would
# render the template `app/views/posts/index.html.erb` by default after
# populating the `@posts` instance variable.
#
# Unlike index, the create action will not render a template. After performing
# its main purpose (creating a new post), it initiates a redirect instead. This
# redirect works by returning an external `302 Moved` HTTP response that takes
# the user to the index action.
#
# These two methods represent the two basic action archetypes used in Action
# Controllers: Get-and-show and do-and-redirect. Most actions are variations on
# these themes.
#
# ## Requests
#
# For every request, the router determines the value of the `controller` and
# `action` keys. These determine which controller and action are called. The
# remaining request parameters, the session (if one is available), and the full
# request with all the HTTP headers are made available to the action through
# accessor methods. Then the action is performed.
#
# The full request object is available via the request accessor and is primarily
# used to query for HTTP headers:
#
# def server_ip
# location = request.env["REMOTE_ADDR"]
# render plain: "This server hosted at #{location}"
# end
#
# ## Parameters
#
# All request parameters, whether they come from a query string in the URL or
# form data submitted through a POST request are available through the `params`
# method which returns a hash. For example, an action that was performed through
# `/posts?category=All&limit=5` will include `{ "category" => "All", "limit" =>
# "5" }` in `params`.
#
# It's also possible to construct multi-dimensional parameter hashes by
# specifying keys using brackets, such as:
#
#
#
#
# A request coming from a form holding these inputs will include `{ "post" => {
# "name" => "david", "address" => "hyacintvej" } }`. If the address input had
# been named `post[address][street]`, the `params` would have included `{ "post"
# => { "address" => { "street" => "hyacintvej" } } }`. There's no limit to the
# depth of the nesting.
#
# ## Sessions
#
# Sessions allow you to store objects in between requests. This is useful for
# objects that are not yet ready to be persisted, such as a Signup object
# constructed in a multi-paged process, or objects that don't change much and
# are needed all the time, such as a User object for a system that requires
# login. The session should not be used, however, as a cache for objects where
# it's likely they could be changed unknowingly. It's usually too much work to
# keep it all synchronized -- something databases already excel at.
#
# You can place objects in the session by using the `session` method, which
# accesses a hash:
#
# session[:person] = Person.authenticate(user_name, password)
#
# You can retrieve it again through the same hash:
#
# "Hello #{session[:person]}"
#
# For removing objects from the session, you can either assign a single key to
# `nil`:
#
# # removes :person from session
# session[:person] = nil
#
# or you can remove the entire session with `reset_session`.
#
# By default, sessions are stored in an encrypted browser cookie (see
# ActionDispatch::Session::CookieStore). Thus the user will not be able to read
# or edit the session data. However, the user can keep a copy of the cookie even
# after it has expired, so you should avoid storing sensitive information in
# cookie-based sessions.
#
# ## Responses
#
# Each action results in a response, which holds the headers and document to be
# sent to the user's browser. The actual response object is generated
# automatically through the use of renders and redirects and requires no user
# intervention.
#
# ## Renders
#
# Action Controller sends content to the user by using one of five rendering
# methods. The most versatile and common is the rendering of a template.
# Included in the Action Pack is the Action View, which enables rendering of ERB
# templates. It's automatically configured. The controller passes objects to the
# view by assigning instance variables:
#
# def show
# @post = Post.find(params[:id])
# end
#
# Which are then automatically available to the view:
#
# Title: <%= @post.title %>
#
# You don't have to rely on the automated rendering. For example, actions that
# could result in the rendering of different templates will use the manual
# rendering methods:
#
# def search
# @results = Search.find(params[:query])
# case @results.count
# when 0 then render action: "no_results"
# when 1 then render action: "show"
# when 2..10 then render action: "show_many"
# end
# end
#
# Read more about writing ERB and Builder templates in ActionView::Base.
#
# ## Redirects
#
# Redirects are used to move from one action to another. For example, after a
# `create` action, which stores a blog entry to the database, we might like to
# show the user the new entry. Because we're following good DRY principles
# (Don't Repeat Yourself), we're going to reuse (and redirect to) a `show`
# action that we'll assume has already been created. The code might look like
# this:
#
# def create
# @entry = Entry.new(params[:entry])
# if @entry.save
# # The entry was saved correctly, redirect to show
# redirect_to action: 'show', id: @entry.id
# else
# # things didn't go so well, do something else
# end
# end
#
# In this case, after saving our new entry to the database, the user is
# redirected to the `show` method, which is then executed. Note that this is an
# external HTTP-level redirection which will cause the browser to make a second
# request (a GET to the show action), and not some internal re-routing which
# calls both "create" and then "show" within one request.
#
# Learn more about `redirect_to` and what options you have in
# ActionController::Redirecting.
#
# ## Calling multiple redirects or renders
#
# An action may contain only a single render or a single redirect. Attempting to
# try to do either again will result in a DoubleRenderError:
#
# def do_something
# redirect_to action: "elsewhere"
# render action: "overthere" # raises DoubleRenderError
# end
#
# If you need to redirect on the condition of something, then be sure to add
# "and return" to halt execution.
#
# def do_something
# redirect_to(action: "elsewhere") and return if monkeys.nil?
# render action: "overthere" # won't be called if monkeys is nil
# end
#
class Base < Metal
abstract!
# Shortcut helper that returns all the modules included in
# ActionController::Base except the ones passed as arguments:
#
# class MyBaseController < ActionController::Metal
# ActionController::Base.without_modules(:ParamsWrapper, :Streaming).each do |left|
# include left
# end
# end
#
# This gives better control over what you want to exclude and makes it easier to
# create a bare controller class, instead of listing the modules required
# manually.
def self.without_modules(*modules)
modules = modules.map do |m|
m.is_a?(Symbol) ? ActionController.const_get(m) : m
end
MODULES - modules
end
MODULES = [
AbstractController::Rendering,
AbstractController::Translation,
AbstractController::AssetPaths,
Helpers,
UrlFor,
Redirecting,
ActionView::Layouts,
Rendering,
Renderers::All,
ConditionalGet,
EtagWithTemplateDigest,
EtagWithFlash,
Caching,
MimeResponds,
ImplicitRender,
StrongParameters,
ParameterEncoding,
Cookies,
Flash,
FormBuilder,
RequestForgeryProtection,
ContentSecurityPolicy,
PermissionsPolicy,
RateLimiting,
AllowBrowser,
Streaming,
DataStreaming,
HttpAuthentication::Basic::ControllerMethods,
HttpAuthentication::Digest::ControllerMethods,
HttpAuthentication::Token::ControllerMethods,
DefaultHeaders,
Logging,
# Before callbacks should also be executed as early as possible, so also include
# them at the bottom.
AbstractController::Callbacks,
# Append rescue at the bottom to wrap as much as possible.
Rescue,
# Add instrumentations hooks at the bottom, to ensure they instrument all the
# methods properly.
Instrumentation,
# Params wrapper should come before instrumentation so they are properly showed
# in logs
ParamsWrapper
]
MODULES.each do |mod|
include mod
end
setup_renderer!
# Define some internal variables that should not be propagated to the view.
PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + %i(
@_params @_response @_request @_config @_url_options @_action_has_layout @_view_context_class
@_view_renderer @_lookup_context @_routes @_view_runtime @_db_runtime @_helper_proxy
@_marked_for_same_origin_verification @_rendered_format
)
def _protected_ivars
PROTECTED_IVARS
end
private :_protected_ivars
ActiveSupport.run_load_hooks(:action_controller_base, self)
ActiveSupport.run_load_hooks(:action_controller, self)
end
end