# The generated code is based on Ruby on Rails source code # You can find the license of Ruby on Rails from following. #Copyright (c) 2005-2019 David Heinemeier Hansson # #Permission is hereby granted, free of charge, to any person obtaining #a copy of this software and associated documentation files (the #"Software"), to deal in the Software without restriction, including #without limitation the rights to use, copy, modify, merge, publish, #distribute, sublicense, and/or sell copies of the Software, and to #permit persons to whom the Software is furnished to do so, subject to #the following conditions: # #The above copyright notice and this permission notice shall be #included in all copies or substantial portions of the Software. # #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF #MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE #LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION #OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION #WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. module AbstractController module AssetPaths # nodoc: extend ActiveSupport::Concern end end module AbstractController # Raised when a non-existing controller action is triggered. class ActionNotFound < StandardError end # AbstractController::Base is a low-level API. Nobody should be # using it directly, and subclasses (like ActionController::Base) are # expected to provide their own +render+ method, since rendering means # different things depending on the context. class Base # # Returns the body of the HTTP response sent by the controller. attr_accessor response_body(@_response_body): untyped # # Returns the name of the action this controller is processing. attr_accessor action_name(@_action_name): untyped # # Returns the formats that can be processed by the controller. attr_accessor formats(@_formats): untyped include ActiveSupport::Configurable extend ActiveSupport::DescendantsTracker attr_reader self.abstract: untyped alias self.abstract? self.abstract # Define a controller as abstract. See internal_methods for more # details. def self.abstract!: () -> untyped def self.inherited: (untyped klass) -> untyped # A list of all internal methods for a controller. This finds the first # abstract superclass of a controller, and gets a list of all public # instance methods on that abstract class. Public instance methods of # a controller would normally be considered action methods, so methods # declared on abstract classes are being removed. # (ActionController::Metal and ActionController::Base are defined as abstract) def self.internal_methods: () -> untyped # A list of method names that should be considered actions. This # includes all public instance methods on a controller, less # any internal methods (see internal_methods), adding back in # any methods that are internal, but still exist on the class # itself. # # ==== Returns # * Set - A set of all methods that should be considered actions. def self.action_methods: () -> untyped # action_methods are cached and there is sometimes a need to refresh # them. ::clear_action_methods! allows you to do that, so next time # you run action_methods, they will be recalculated. def self.clear_action_methods!: () -> untyped # Returns the full controller name, underscored, without the ending Controller. # # class MyApp::MyPostsController < AbstractController::Base # # end # # MyApp::MyPostsController.controller_path # => "my_app/my_posts" # # ==== Returns # * String def self.controller_path: () -> untyped # Refresh the cached action_methods when a new action_method is added. def self.method_added: (untyped name) -> untyped # Calls the action going through the entire action dispatch stack. # # The actual method that is called is determined by calling # #method_for_action. If no method can handle the action, then an # AbstractController::ActionNotFound error is raised. # # ==== Returns # * self def process: (untyped action, *untyped args) -> untyped # Delegates to the class' ::controller_path def controller_path: () -> untyped # Delegates to the class' ::action_methods def action_methods: () -> untyped # Returns true if a method for the action is available and # can be dispatched, false otherwise. # # Notice that action_methods.include?("foo") may return # false and available_action?("foo") returns true because # this method considers actions that are also available # through other means, for example, implicit render ones. # # ==== Parameters # * action_name - The name of an action to be tested def available_action?: (untyped action_name) -> untyped # Tests if a response body is set. Used to determine if the # +process_action+ callback needs to be terminated in # +AbstractController::Callbacks+. def performed?: () -> untyped # Returns true if the given controller is capable of rendering # a path. A subclass of +AbstractController::Base+ # may return false. An Email controller for example does not # support paths, only full URLs. def self.supports_path?: () -> ::TrueClass private # Returns true if the name can be considered an action because # it has a method defined in the controller. # # ==== Parameters # * name - The name of an action to be tested def action_method?: (untyped name) -> untyped # Call the action. Override this in a subclass to modify the # behavior around processing an action. This, and not #process, # is the intended way to override action dispatching. # # Notice that the first argument is the method to be dispatched # which is *not* necessarily the same as the action name. def process_action: (untyped method_name, *untyped args) -> untyped # Actually call the method associated with the action. Override # this method if you wish to change how action methods are called, # not to add additional behavior around it. For example, you would # override #send_action if you want to inject arguments into the # method. alias send_action send # If the action name was not found, but a method called "action_missing" # was found, #method_for_action will return "_handle_action_missing". # This method calls #action_missing with the current action name. def _handle_action_missing: (*untyped args) -> untyped # Takes an action name and returns the name of the method that will # handle the action. # # It checks if the action name is valid and returns false otherwise. # # See method_for_action for more information. # # ==== Parameters # * action_name - An action name to find a method name for # # ==== Returns # * string - The name of the method that handles the action # * false - No valid method name could be found. # Raise +AbstractController::ActionNotFound+. def _find_action_name: (untyped action_name) -> untyped # Takes an action name and returns the name of the method that will # handle the action. In normal cases, this method returns the same # name as it receives. By default, if #method_for_action receives # a name that is not an action, it will look for an #action_missing # method and return "_handle_action_missing" if one is found. # # Subclasses may override this method to add additional conditions # that should be considered an action. For instance, an HTTP controller # with a template matching the action name is considered to exist. # # If you override this method to handle additional cases, you may # also provide a method (like +_handle_method_missing+) to handle # the case. # # If none of these conditions are true, and +method_for_action+ # returns +nil+, an +AbstractController::ActionNotFound+ exception will be raised. # # ==== Parameters # * action_name - An action name to find a method name for # # ==== Returns # * string - The name of the method that handles the action # * nil - No method name could be found. def method_for_action: (untyped action_name) -> untyped # Checks if the action name is valid and returns false otherwise. def _valid_action_name?: (untyped action_name) -> untyped end end module AbstractController module Caching # Fragment caching is used for caching various blocks within # views without caching the entire action as a whole. This is # useful when certain elements of an action change frequently or # depend on complicated state while other parts rarely change or # can be shared amongst multiple parties. The caching is done using # the +cache+ helper available in the Action View. See # ActionView::Helpers::CacheHelper for more information. # # While it's strongly recommended that you use key-based cache # expiration (see links in CacheHelper for more information), # it is also possible to manually expire caches. For example: # # expire_fragment('name_of_cache') module Fragments extend ActiveSupport::Concern module ClassMethods # Allows you to specify controller-wide key prefixes for # cache fragments. Pass either a constant +value+, or a block # which computes a value each time a cache key is generated. # # For example, you may want to prefix all fragment cache keys # with a global version identifier, so you can easily # invalidate all caches. # # class ApplicationController # fragment_cache_key "v1" # end # # When it's time to invalidate all fragments, simply change # the string constant. Or, progressively roll out the cache # invalidation using a computed value: # # class ApplicationController # fragment_cache_key do # @account.id.odd? ? "v1" : "v2" # end # end def fragment_cache_key: (?untyped? value) { () -> untyped } -> untyped end # Given a key (as described in +expire_fragment+), returns # a key array suitable for use in reading, writing, or expiring a # cached fragment. All keys begin with :views, # followed by ENV["RAILS_CACHE_ID"] or ENV["RAILS_APP_VERSION"] if set, # followed by any controller-wide key prefix values, ending # with the specified +key+ value. def combined_fragment_cache_key: (untyped key) -> untyped # Writes +content+ to the location signified by # +key+ (see +expire_fragment+ for acceptable formats). def write_fragment: (untyped key, untyped content, ?untyped? options) -> untyped # Reads a cached fragment from the location signified by +key+ # (see +expire_fragment+ for acceptable formats). def read_fragment: (untyped key, ?untyped? options) -> (nil | untyped) # Check if a cached fragment from the location signified by # +key+ exists (see +expire_fragment+ for acceptable formats). def fragment_exist?: (untyped key, ?untyped? options) -> (nil | untyped) # Removes fragments from the cache. # # +key+ can take one of three forms: # # * String - This would normally take the form of a path, like # pages/45/notes. # * Hash - Treated as an implicit call to +url_for+, like # { controller: 'pages', action: 'notes', id: 45} # * Regexp - Will remove any fragment that matches, so # %r{pages/\d*/notes} might remove all notes. Make sure you # don't use anchors in the regex (^ or $) because # the actual filename matched looks like # ./cache/filename/path.cache. Note: Regexp expiration is # only supported on caches that can iterate over all keys (unlike # memcached). # # +options+ is passed through to the cache store's +delete+ # method (or delete_matched, for Regexp keys). def expire_fragment: (untyped key, ?untyped? options) -> (nil | untyped) def instrument_fragment_cache: (untyped name, untyped key) { () -> untyped } -> untyped end end end module AbstractController module Caching extend ActiveSupport::Concern extend ActiveSupport::Autoload module ConfigMethods def cache_store: () -> untyped def cache_store=: (untyped store) -> untyped private def cache_configured?: () -> untyped end include ConfigMethods include AbstractController::Caching::Fragments extend ConfigMethods module ClassMethods def view_cache_dependency: () { () -> untyped } -> untyped end def view_cache_dependencies: () -> untyped private def cache: (untyped key, ?::Hash[untyped, untyped] options) { () -> untyped } -> untyped end end module AbstractController # = Abstract Controller Callbacks # # Abstract Controller provides hooks during the life cycle of a controller action. # Callbacks allow you to trigger logic during this cycle. Available callbacks are: # # * after_action # * append_after_action # * append_around_action # * append_before_action # * around_action # * before_action # * prepend_after_action # * prepend_around_action # * prepend_before_action # * skip_after_action # * skip_around_action # * skip_before_action # # NOTE: Calling the same callback multiple times will overwrite previous callback definitions. # module Callbacks extend ActiveSupport::Concern # Uses ActiveSupport::Callbacks as the base functionality. For # more details on the whole callback system, read the documentation # for ActiveSupport::Callbacks. include ActiveSupport::Callbacks # Override AbstractController::Base#process_action to run the # process_action callbacks around the normal behavior. def process_action: (*untyped args) -> untyped module ClassMethods # If +:only+ or +:except+ are used, convert the options into the # +:if+ and +:unless+ options of ActiveSupport::Callbacks. # # The basic idea is that :only => :index gets converted to # :if => proc {|c| c.action_name == "index" }. # # Note that :only has priority over :if in case they # are used together. # # only: :index, if: -> { true } # the :if option will be ignored. # # Note that :if has priority over :except in case they # are used together. # # except: :index, if: -> { true } # the :except option will be ignored. # # ==== Options # * only - The callback should be run only for this action. # * except - The callback should be run for all actions except this action. def _normalize_callback_options: (untyped options) -> untyped def _normalize_callback_option: (untyped options, untyped from, untyped to) -> untyped # Take callback names and an optional callback proc, normalize them, # then call the block with each callback. This allows us to abstract # the normalization across several methods that use it. # # ==== Parameters # * callbacks - An array of callbacks, with an optional # options hash as the last parameter. # * block - A proc that should be added to the callbacks. # # ==== Block Parameters # * name - The callback to be added. # * options - A hash of options to be used when adding the callback. def _insert_callbacks: (untyped callbacks, ?untyped? block) { (untyped, untyped) -> untyped } -> untyped end end end module AbstractController module Collector def self.generate_method_for_mime: (untyped mime) -> untyped private def method_missing: (untyped symbol) { () -> untyped } -> untyped end end module AbstractController class Error < StandardError end end module AbstractController module Helpers extend ActiveSupport::Concern class MissingHelperError < LoadError def initialize: (untyped error, untyped path) -> untyped end module ClassMethods # When a class is inherited, wrap its helper module in a new module. # This ensures that the parent class's module can be changed # independently of the child class's. def inherited: (untyped klass) -> untyped # Declare a controller method as a helper. For example, the following # makes the +current_user+ and +logged_in?+ controller methods available # to the view: # class ApplicationController < ActionController::Base # helper_method :current_user, :logged_in? # # def current_user # @current_user ||= User.find_by(id: session[:user]) # end # # def logged_in? # current_user != nil # end # end # # In a view: # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%> # # ==== Parameters # * method[, method] - A name or names of a method on the controller # to be made available on the view. def helper_method: (*untyped meths) -> untyped # The +helper+ class method can take a series of helper module names, a block, or both. # # ==== Options # * *args - Module, Symbol, String # * block - A block defining helper methods # # When the argument is a module it will be included directly in the template class. # helper FooHelper # => includes FooHelper # # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file # and include the module in the template class. The second form illustrates how to include custom helpers # when working with namespaced controllers, or other cases where the file containing the helper definition is not # in one of Rails' standard load paths: # helper :foo # => requires 'foo_helper' and includes FooHelper # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper # # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available # to the template. # # # One line # helper { def hello() "Hello, world!" end } # # # Multi-line # helper do # def foo(bar) # "#{bar} is the very best" # end # end # # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of # +symbols+, +strings+, +modules+ and blocks. # # helper(:three, BlindHelper) { def mice() 'mice' end } # def helper: (*untyped args) { () -> untyped } -> untyped # Clears up all existing helpers in this class, only keeping the helper # with the same name as this class. def clear_helpers: () -> untyped # Returns a list of modules, normalized from the acceptable kinds of # helpers with the following behavior: # # String or Symbol:: :FooBar or "FooBar" becomes "foo_bar_helper", # and "foo_bar_helper.rb" is loaded using require_dependency. # # Module:: No further processing # # After loading the appropriate files, the corresponding modules # are returned. # # ==== Parameters # * args - An array of helpers # # ==== Returns # * Array - A normalized list of modules for the list of # helpers provided. def modules_for_helpers: (untyped args) -> untyped private # Makes all the (instance) methods in the helper module available to templates # rendered through this controller. # # ==== Parameters # * module - The module to include into the current helper module # for the class def add_template_helper: (untyped mod) -> untyped def default_helper_module!: () -> untyped end end end module AbstractController module Logger # nodoc: extend ActiveSupport::Concern include ActiveSupport::Benchmarkable end end module AbstractController module Railties module RoutesHelpers def self.with: (untyped routes, ?bool include_path_helpers) -> untyped end end end module AbstractController class DoubleRenderError < Error DEFAULT_MESSAGE: ::String def initialize: (?untyped? message) -> untyped end module Rendering extend ActiveSupport::Concern include ActionView::ViewPaths # Normalizes arguments, options and then delegates render_to_body and # sticks the result in self.response_body. def render: (*untyped args) { () -> untyped } -> untyped # Raw rendering of a template to a string. # # It is similar to render, except that it does not # set the +response_body+ and it should be guaranteed # to always return a string. # # If a component extends the semantics of +response_body+ # (as ActionController extends it to be anything that # responds to the method each), this method needs to be # overridden in order to still return a string. def render_to_string: (*untyped args) { () -> untyped } -> untyped # Performs the actual template rendering. def render_to_body: (?::Hash[untyped, untyped] options) -> nil # Returns Content-Type of rendered content. def rendered_format: () -> untyped DEFAULT_PROTECTED_INSTANCE_VARIABLES: untyped # This method should return a hash with assigns. # You can overwrite this configuration per controller. def view_assigns: () -> untyped private def _normalize_args: (?untyped? action, ?::Hash[untyped, untyped] options) -> untyped def _normalize_options: (untyped options) -> untyped def _process_options: (untyped options) -> untyped def _process_format: (untyped format) -> nil def _process_variant: (untyped options) -> nil def _set_html_content_type: () -> nil def _set_rendered_content_type: (untyped format) -> nil def _normalize_render: (*untyped args) { () -> untyped } -> untyped def _protected_ivars: () -> untyped end end module AbstractController module Translation # Delegates to I18n.translate. Also aliased as t. # # When the given key starts with a period, it will be scoped by the current # controller and action. So if you call translate(".foo") from # PeopleController#index, it will convert the call to # I18n.translate("people.index.foo"). This makes it less repetitive # to translate many keys within the same controller / action and gives you a # simple framework for scoping them consistently. def translate: (untyped key, **untyped options) -> untyped alias t translate # Delegates to I18n.localize. Also aliased as l. def localize: (untyped object, **untyped options) -> untyped alias l localize end end module AbstractController # Includes +url_for+ into the host class (e.g. an abstract controller or mailer). The class # has to provide a +RouteSet+ by implementing the _routes methods. Otherwise, an # exception will be raised. # # Note that this module is completely decoupled from HTTP - the only requirement is a valid # _routes implementation. module UrlFor extend ActiveSupport::Concern include ActionDispatch::Routing::UrlFor def _routes: () -> untyped module ClassMethods def _routes: () -> nil def action_methods: () -> untyped end end end module AbstractController extend ActiveSupport::Autoload def self.eager_load!: () -> untyped end module ActionController module ApiRendering extend ActiveSupport::Concern include Rendering def render_to_body: (?::Hash[untyped, untyped] options) -> untyped end end module ActionController # API Controller is a lightweight version of ActionController::Base, # created for applications that don't require all functionalities that a complete # \Rails controller provides, allowing you to create controllers with just the # features that you need for API only applications. # # An API Controller is different from a normal controller in the sense that # by default it doesn't include a number of features that are usually required # by browser access only: layouts and templates rendering, # flash, assets, and so on. This makes the entire controller stack thinner, # suitable for API applications. It doesn't mean you won't have such # features if you need them: they're all available for you to include in # your application, they're just not part of the default API controller stack. # # Normally, +ApplicationController+ is the only controller that inherits from # ActionController::API. All other controllers in turn inherit from # +ApplicationController+. # # A sample controller could look like this: # # class PostsController < ApplicationController # def index # posts = Post.all # render json: posts # end # end # # Request, response, and parameters objects all work the exact same way as # ActionController::Base. # # == Renders # # The default API Controller stack includes all renderers, which means you # can use render :json and brothers freely in your controllers. Keep # in mind that templates are not going to be rendered, so you need to ensure # your controller is calling either render or redirect_to in # all actions, otherwise it will return 204 No Content. # # def show # post = Post.find(params[:id]) # render json: post # end # # == Redirects # # Redirects are used to move from one action to another. You can use the # redirect_to method in your controllers in the same way as in # ActionController::Base. For example: # # def create # redirect_to root_url and return if not_authorized? # # do stuff here # end # # == Adding New Behavior # # In some scenarios you may want to add back some functionality provided by # ActionController::Base that is not present by default in # ActionController::API, for instance MimeResponds. This # module gives you the respond_to method. Adding it is quite simple, # you just need to include the module in a specific controller or in # +ApplicationController+ in case you want it available in your entire # application: # # class ApplicationController < ActionController::API # include ActionController::MimeResponds # end # # class PostsController < ApplicationController # def index # posts = Post.all # # respond_to do |format| # format.json { render json: posts } # format.xml { render xml: posts } # end # end # end # # Make sure to check the modules included in ActionController::Base # if you want to use any other functionality that is not provided # by ActionController::API out of the box. class API < Metal # Shortcut helper that returns all the ActionController::API modules except # the ones passed as arguments: # # class MyAPIBaseController < ActionController::Metal # ActionController::API.without_modules(:ForceSSL, :UrlFor).each do |left| # include left # end # end # # This gives better control over what you want to exclude and makes it easier # to create an API controller class, instead of listing the modules required # manually. def self.without_modules: (*untyped modules) -> untyped MODULES: ::Array[untyped] end end module ActionController # 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+. # # Sessions are stored by default in a browser cookie that's cryptographically signed, but unencrypted. # This prevents the user from tampering with the session but also allows them to see its contents. # # Do not put secret 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 # 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: (*untyped modules) -> untyped MODULES: ::Array[untyped] # Define some internal variables that should not be propagated to the view. PROTECTED_IVARS: untyped def _protected_ivars: () -> untyped end end module ActionController # \Caching is a cheap way of speeding up slow applications by keeping the result of # calculations, renderings, and database calls around for subsequent requests. # # You can read more about each approach by clicking the modules below. # # Note: To turn off all caching provided by Action Controller, set # config.action_controller.perform_caching = false # # == \Caching stores # # All the caching stores from ActiveSupport::Cache are available to be used as backends # for Action Controller caching. # # Configuration examples (FileStore is the default): # # config.action_controller.cache_store = :memory_store # config.action_controller.cache_store = :file_store, '/path/to/cache/directory' # config.action_controller.cache_store = :mem_cache_store, 'localhost' # config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211') # config.action_controller.cache_store = MyOwnStore.new('parameter') module Caching extend ActiveSupport::Autoload extend ActiveSupport::Concern include AbstractController::Caching private def instrument_payload: (untyped key) -> { controller: untyped, action: untyped, key: untyped } def instrument_name: () -> "action_controller" end end module ActionController # Override the default form builder for all views rendered by this # controller and any of its descendants. Accepts a subclass of # +ActionView::Helpers::FormBuilder+. # # For example, given a form builder: # # class AdminFormBuilder < ActionView::Helpers::FormBuilder # def special_field(name) # end # end # # The controller specifies a form builder as its default: # # class AdminAreaController < ApplicationController # default_form_builder AdminFormBuilder # end # # Then in the view any form using +form_for+ will be an instance of the # specified form builder: # # <%= form_for(@instance) do |builder| %> # <%= builder.special_field(:name) %> # <% end %> module FormBuilder extend ActiveSupport::Concern module ClassMethods # Set the form builder to be used as the default for all forms # in the views rendered by this controller and its subclasses. # # ==== Parameters # * builder - Default form builder, an instance of +ActionView::Helpers::FormBuilder+ def default_form_builder: (untyped builder) -> untyped end # Default form builder for the controller def default_form_builder: () -> untyped end end module ActionController class LogSubscriber < ActiveSupport::LogSubscriber INTERNAL_PARAMS: ::Array[untyped] def start_processing: (untyped event) -> (nil | untyped) def process_action: (untyped event) -> untyped def halted_callback: (untyped event) -> untyped def send_file: (untyped event) -> untyped def redirect_to: (untyped event) -> untyped def send_data: (untyped event) -> untyped def unpermitted_parameters: (untyped event) -> untyped def logger: () -> untyped end end module ActionController module BasicImplicitRender # :nodoc: def send_action: (untyped method, *untyped args) -> untyped def default_render: () -> untyped end end module ActionController module ConditionalGet extend ActiveSupport::Concern include Head module ClassMethods # Allows you to consider additional controller-wide information when generating an ETag. # For example, if you serve pages tailored depending on who's logged in at the moment, you # may want to add the current user id to be part of the ETag to prevent unauthorized displaying # of cached pages. # # class InvoicesController < ApplicationController # etag { current_user.try :id } # # def show # # Etag will differ even for the same invoice when it's viewed by a different current_user # @invoice = Invoice.find(params[:id]) # fresh_when(@invoice) # end # end def etag: () { () -> untyped } -> untyped end # Sets the +etag+, +last_modified+, or both on the response and renders a # 304 Not Modified response if the request is already fresh. # # === Parameters: # # * :etag Sets a "weak" ETag validator on the response. See the # +:weak_etag+ option. # * :weak_etag Sets a "weak" ETag validator on the response. # Requests that set If-None-Match header may return a 304 Not Modified # response if it matches the ETag exactly. A weak ETag indicates semantic # equivalence, not byte-for-byte equality, so they're good for caching # HTML pages in browser caches. They can't be used for responses that # must be byte-identical, like serving Range requests within a PDF file. # * :strong_etag Sets a "strong" ETag validator on the response. # Requests that set If-None-Match header may return a 304 Not Modified # response if it matches the ETag exactly. A strong ETag implies exact # equality: the response must match byte for byte. This is necessary for # doing Range requests within a large video or PDF file, for example, or # for compatibility with some CDNs that don't support weak ETags. # * :last_modified Sets a "weak" last-update validator on the # response. Subsequent requests that set If-Modified-Since may return a # 304 Not Modified response if last_modified <= If-Modified-Since. # * :public By default the Cache-Control header is private, set this to # +true+ if you want your application to be cacheable by other devices (proxy caches). # * :template By default, the template digest for the current # controller/action is included in ETags. If the action renders a # different template, you can include its digest instead. If the action # doesn't render a template at all, you can pass template: false # to skip any attempt to check for a template digest. # # === Example: # # def show # @article = Article.find(params[:id]) # fresh_when(etag: @article, last_modified: @article.updated_at, public: true) # end # # This will render the show template if the request isn't sending a matching ETag or # If-Modified-Since header and just a 304 Not Modified response if there's a match. # # You can also just pass a record. In this case +last_modified+ will be set # by calling +updated_at+ and +etag+ by passing the object itself. # # def show # @article = Article.find(params[:id]) # fresh_when(@article) # end # # You can also pass an object that responds to +maximum+, such as a # collection of active records. In this case +last_modified+ will be set by # calling maximum(:updated_at) on the collection (the timestamp of the # most recently updated record) and the +etag+ by passing the object itself. # # def index # @articles = Article.all # fresh_when(@articles) # end # # When passing a record or a collection, you can still set the public header: # # def show # @article = Article.find(params[:id]) # fresh_when(@article, public: true) # end # # When rendering a different template than the default controller/action # style, you can indicate which digest to include in the ETag: # # before_action { fresh_when @article, template: 'widgets/show' } # def fresh_when: (?untyped? object, ?template: untyped? template, ?public: bool `public`, ?last_modified: untyped? last_modified, ?strong_etag: untyped? strong_etag, ?weak_etag: untyped? weak_etag, ?etag: untyped? etag) -> untyped # Sets the +etag+ and/or +last_modified+ on the response and checks it against # the client request. If the request doesn't match the options provided, the # request is considered stale and should be generated from scratch. Otherwise, # it's fresh and we don't need to generate anything and a reply of 304 Not Modified is sent. # # === Parameters: # # * :etag Sets a "weak" ETag validator on the response. See the # +:weak_etag+ option. # * :weak_etag Sets a "weak" ETag validator on the response. # Requests that set If-None-Match header may return a 304 Not Modified # response if it matches the ETag exactly. A weak ETag indicates semantic # equivalence, not byte-for-byte equality, so they're good for caching # HTML pages in browser caches. They can't be used for responses that # must be byte-identical, like serving Range requests within a PDF file. # * :strong_etag Sets a "strong" ETag validator on the response. # Requests that set If-None-Match header may return a 304 Not Modified # response if it matches the ETag exactly. A strong ETag implies exact # equality: the response must match byte for byte. This is necessary for # doing Range requests within a large video or PDF file, for example, or # for compatibility with some CDNs that don't support weak ETags. # * :last_modified Sets a "weak" last-update validator on the # response. Subsequent requests that set If-Modified-Since may return a # 304 Not Modified response if last_modified <= If-Modified-Since. # * :public By default the Cache-Control header is private, set this to # +true+ if you want your application to be cacheable by other devices (proxy caches). # * :template By default, the template digest for the current # controller/action is included in ETags. If the action renders a # different template, you can include its digest instead. If the action # doesn't render a template at all, you can pass template: false # to skip any attempt to check for a template digest. # # === Example: # # def show # @article = Article.find(params[:id]) # # if stale?(etag: @article, last_modified: @article.updated_at) # @statistics = @article.really_expensive_call # respond_to do |format| # # all the supported formats # end # end # end # # You can also just pass a record. In this case +last_modified+ will be set # by calling +updated_at+ and +etag+ by passing the object itself. # # def show # @article = Article.find(params[:id]) # # if stale?(@article) # @statistics = @article.really_expensive_call # respond_to do |format| # # all the supported formats # end # end # end # # You can also pass an object that responds to +maximum+, such as a # collection of active records. In this case +last_modified+ will be set by # calling +maximum(:updated_at)+ on the collection (the timestamp of the # most recently updated record) and the +etag+ by passing the object itself. # # def index # @articles = Article.all # # if stale?(@articles) # @statistics = @articles.really_expensive_call # respond_to do |format| # # all the supported formats # end # end # end # # When passing a record or a collection, you can still set the public header: # # def show # @article = Article.find(params[:id]) # # if stale?(@article, public: true) # @statistics = @article.really_expensive_call # respond_to do |format| # # all the supported formats # end # end # end # # When rendering a different template than the default controller/action # style, you can indicate which digest to include in the ETag: # # def show # super if stale? @article, template: 'widgets/show' # end # def stale?: (?untyped? object, **untyped freshness_kwargs) -> untyped # Sets an HTTP 1.1 Cache-Control header. Defaults to issuing a +private+ # instruction, so that intermediate caches must not cache the response. # # expires_in 20.minutes # expires_in 3.hours, public: true # expires_in 3.hours, public: true, must_revalidate: true # # This method will overwrite an existing Cache-Control header. # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities. # # HTTP Cache-Control Extensions for Stale Content. See https://tools.ietf.org/html/rfc5861 # It helps to cache an asset and serve it while is being revalidated and/or returning with an error. # # expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds # expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds, stale_if_error: 5.minutes # # The method will also ensure an HTTP Date header for client compatibility. def expires_in: (untyped seconds, ?::Hash[untyped, untyped] options) -> untyped # Sets an HTTP 1.1 Cache-Control header of no-cache. This means the # resource will be marked as stale, so clients must always revalidate. # Intermediate/browser caches may still store the asset. def expires_now: () -> untyped # Cache or yield the block. The cache is supposed to never expire. # # You can use this method when you have an HTTP response that never changes, # and the browser and proxies should cache it indefinitely. # # * +public+: By default, HTTP responses are private, cached only on the # user's web browser. To allow proxies to cache the response, set +true+ to # indicate that they can serve the cached response to all users. def http_cache_forever: (?public: bool `public`) { () -> untyped } -> untyped private def combine_etags: (untyped validator, untyped options) -> untyped end end module ActionController # nodoc: module ContentSecurityPolicy # TODO: Documentation extend ActiveSupport::Concern include AbstractController::Helpers include AbstractController::Callbacks module ClassMethods def content_security_policy: (?bool enabled, **untyped options) { (untyped) -> untyped } -> untyped def content_security_policy_report_only: (?bool report_only, **untyped options) -> untyped end private def content_security_policy?: () -> untyped def content_security_policy_nonce: () -> untyped def current_content_security_policy: () -> untyped end end module ActionController # nodoc: module Cookies extend ActiveSupport::Concern private def cookies: () -> untyped end end module ActionController # nodoc: # Methods for sending arbitrary data and for streaming files to the browser, # instead of rendering. module DataStreaming extend ActiveSupport::Concern include ActionController::Rendering DEFAULT_SEND_FILE_TYPE: ::String DEFAULT_SEND_FILE_DISPOSITION: ::String private def send_file: (untyped path, ?::Hash[untyped, untyped] options) -> untyped def send_data: (untyped data, ?::Hash[untyped, untyped] options) -> untyped def send_file_headers!: (untyped options) -> untyped end end module ActionController # Allows configuring default headers that will be automatically merged into # each response. module DefaultHeaders extend ActiveSupport::Concern module ClassMethods def make_response!: (untyped request) -> untyped end end end module ActionController # When you're using the flash, it's generally used as a conditional on the view. # This means the content of the view depends on the flash. Which in turn means # that the ETag for a response should be computed with the content of the flash # in mind. This does that by including the content of the flash as a component # in the ETag that's generated for a response. module EtagWithFlash extend ActiveSupport::Concern include ActionController::ConditionalGet end end module ActionController # When our views change, they should bubble up into HTTP cache freshness # and bust browser caches. So the template digest for the current action # is automatically included in the ETag. # # Enabled by default for apps that use Action View. Disable by setting # # config.action_controller.etag_with_template_digest = false # # Override the template to digest by passing +:template+ to +fresh_when+ # and +stale?+ calls. For example: # # # We're going to render widgets/show, not posts/show # fresh_when @post, template: 'widgets/show' # # # We're not going to render a template, so omit it from the ETag. # fresh_when @post, template: false # module EtagWithTemplateDigest extend ActiveSupport::Concern include ActionController::ConditionalGet private def determine_template_etag: (untyped options) -> untyped # Pick the template digest to include in the ETag. If the +:template+ option # is present, use the named template. If +:template+ is +nil+ or absent, use # the default controller/action template. If +:template+ is false, omit the # template digest from the ETag. def pick_template_for_etag: (untyped options) -> untyped def lookup_and_digest_template: (untyped template) -> untyped end end module ActionController class ActionControllerError < StandardError end class BadRequest < ActionControllerError # nodoc: def initialize: (?untyped? msg) -> untyped end class RenderError < ActionControllerError end class RoutingError < ActionControllerError # nodoc: attr_reader failures: untyped def initialize: (untyped message, ?untyped failures) -> untyped end class UrlGenerationError < ActionControllerError end class MethodNotAllowed < ActionControllerError # nodoc: def initialize: (*untyped allowed_methods) -> untyped end class NotImplemented < MethodNotAllowed end class MissingFile < ActionControllerError end class SessionOverflowError < ActionControllerError # nodoc: DEFAULT_MESSAGE: ::String def initialize: (?untyped? message) -> untyped end class UnknownHttpMethod < ActionControllerError end class UnknownFormat < ActionControllerError end # Raised when a nested respond_to is triggered and the content types of each # are incompatible. For example: # # respond_to do |outer_type| # outer_type.js do # respond_to do |inner_type| # inner_type.html { render body: "HTML" } # end # end # end class RespondToMismatchError < ActionControllerError DEFAULT_MESSAGE: ::String def initialize: (?untyped? message) -> untyped end class MissingExactTemplate < UnknownFormat end end module ActionController # nodoc: module Flash extend ActiveSupport::Concern module ClassMethods # Creates new flash types. You can pass as many types as you want to create # flash types other than the default alert and notice in # your controllers and views. For instance: # # # in application_controller.rb # class ApplicationController < ActionController::Base # add_flash_types :warning # end # # # in your controller # redirect_to user_path(@user), warning: "Incomplete profile" # # # in your view # <%= warning %> # # This method will automatically define a new method for each of the given # names, and it will be available in your views. def add_flash_types: (*untyped types) -> untyped end private def redirect_to: (?::Hash[untyped, untyped] options, ?::Hash[untyped, untyped] response_options_and_flash) -> untyped end end module ActionController module ForceSSL # This module is deprecated in favor of +config.force_ssl+ in your environment # config file. This will ensure all endpoints not explicitly marked otherwise # will have all communication served over HTTPS. # :nodoc: extend ActiveSupport::Concern include AbstractController::Callbacks ACTION_OPTIONS: ::Array[untyped] URL_OPTIONS: ::Array[untyped] REDIRECT_OPTIONS: ::Array[untyped] module ClassMethods # :nodoc: def force_ssl: (?::Hash[untyped, untyped] options) -> untyped end def force_ssl_redirect: (?untyped? host_or_options) -> untyped end end module ActionController module Head # Returns a response that has no content (merely headers). The options # argument is interpreted to be a hash of header names and values. # This allows you to easily return a response that consists only of # significant headers: # # head :created, location: person_path(@person) # # head :created, location: @person # # It can also be used to return exceptional conditions: # # return head(:method_not_allowed) unless request.post? # return head(:bad_request) unless valid_request? # render # # See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list of valid +status+ symbols. def head: (untyped status, ?::Hash[untyped, untyped] options) -> ::TrueClass private def include_content?: (untyped status) -> untyped end end module ActionController # The \Rails framework provides a large number of helpers for working with assets, dates, forms, # numbers and model objects, to name a few. These helpers are available to all templates # by default. # # In addition to using the standard template helpers provided, creating custom helpers to # extract complicated logic or reusable functionality is strongly encouraged. By default, each controller # will include all helpers. These helpers are only accessible on the controller through #helpers # # In previous versions of \Rails the controller will include a helper which # matches the name of the controller, e.g., MyController will automatically # include MyHelper. To return old behavior set +config.action_controller.include_all_helpers+ to +false+. # # Additional helpers can be specified using the +helper+ class method in ActionController::Base or any # controller which inherits from it. # # The +to_s+ method from the \Time class can be wrapped in a helper method to display a custom message if # a \Time object is blank: # # module FormattedTimeHelper # def format_time(time, format=:long, blank_message=" ") # time.blank? ? blank_message : time.to_s(format) # end # end # # FormattedTimeHelper can now be included in a controller, using the +helper+ class method: # # class EventsController < ActionController::Base # helper FormattedTimeHelper # def index # @events = Event.all # end # end # # Then, in any view rendered by EventsController, the format_time method can be called: # # <% @events.each do |event| -%> #
# <%= format_time(event.time, :short, "N/A") %> | <%= event.name %> #
# <% end -%> # # Finally, assuming we have two event instances, one which has a time and one which does not, # the output might look like this: # # 23 Aug 11:30 | Carolina Railhawks Soccer Match # N/A | Carolina Railhawks Training Workshop # module Helpers extend ActiveSupport::Concern attr_accessor self.helpers_path: untyped include AbstractController::Helpers module ClassMethods # Declares helper accessors for controller attributes. For example, the # following adds new +name+ and name= instance methods to a # controller and makes them available to the view: # attr_accessor :name # helper_attr :name # # ==== Parameters # * attrs - Names of attributes to be converted into helpers. def helper_attr: (*untyped attrs) -> untyped # Provides a proxy to access helper methods from outside the view. def helpers: () -> untyped # Overwrite modules_for_helpers to accept :all as argument, which loads # all helpers in helpers_path. # # ==== Parameters # * args - A list of helpers # # ==== Returns # * array - A normalized list of modules for the list of helpers provided. def modules_for_helpers: (untyped args) -> untyped # Returns a list of helper names in a given path. # # ActionController::Base.all_helpers_from_path 'app/helpers' # # => ["application", "chart", "rubygems"] def all_helpers_from_path: (untyped path) -> untyped private # Extract helper names from files in app/helpers/**/*_helper.rb def all_application_helpers: () -> untyped end # Provides a proxy to access helper methods from outside the view. def helpers: () -> untyped end end module ActionController # Makes it dead easy to do HTTP Basic, Digest and Token authentication. module HttpAuthentication # Makes it dead easy to do HTTP \Basic authentication. # # === Simple \Basic example # # class PostsController < ApplicationController # http_basic_authenticate_with name: "dhh", password: "secret", except: :index # # def index # render plain: "Everyone can see me!" # end # # def edit # render plain: "I'm only accessible if you know the password" # end # end # # === Advanced \Basic example # # Here is a more advanced \Basic example where only Atom feeds and the XML API is protected by HTTP authentication, # the regular HTML interface is protected by a session approach: # # class ApplicationController < ActionController::Base # before_action :set_account, :authenticate # # private # def set_account # @account = Account.find_by(url_name: request.subdomains.first) # end # # def authenticate # case request.format # when Mime[:xml], Mime[:atom] # if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) } # @current_user = user # else # request_http_basic_authentication # end # else # if session_authenticated? # @current_user = @account.users.find(session[:authenticated][:user_id]) # else # redirect_to(login_url) and return false # end # end # end # end # # In your integration tests, you can do something like this: # # def test_access_granted_from_xml # authorization = ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password) # # get "/notes/1.xml", headers: { 'HTTP_AUTHORIZATION' => authorization } # # assert_equal 200, status # end module Basic extend ::ActionController::HttpAuthentication::Basic module ControllerMethods extend ActiveSupport::Concern module ClassMethods def http_basic_authenticate_with: (password: untyped password, name: untyped name, ?realm: untyped? realm, **untyped options) -> untyped end def http_basic_authenticate_or_request_with: (password: untyped password, name: untyped name, ?message: untyped? message, ?realm: untyped? realm) -> untyped def authenticate_or_request_with_http_basic: (?untyped? realm, ?untyped? message) { () -> untyped } -> untyped def authenticate_with_http_basic: () { () -> untyped } -> untyped def request_http_basic_authentication: (?::String realm, ?untyped? message) -> untyped end def authenticate: (untyped request) { () -> untyped } -> untyped def has_basic_credentials?: (untyped request) -> untyped def user_name_and_password: (untyped request) -> untyped def decode_credentials: (untyped request) -> untyped def auth_scheme: (untyped request) -> untyped def auth_param: (untyped request) -> untyped def encode_credentials: (untyped user_name, untyped password) -> ::String def authentication_request: (untyped controller, untyped realm, untyped message) -> untyped end # Makes it dead easy to do HTTP \Digest authentication. # # === Simple \Digest example # # require 'digest/md5' # class PostsController < ApplicationController # REALM = "SuperSecret" # USERS = {"dhh" => "secret", #plain text password # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password # # before_action :authenticate, except: [:index] # # def index # render plain: "Everyone can see me!" # end # # def edit # render plain: "I'm only accessible if you know the password" # end # # private # def authenticate # authenticate_or_request_with_http_digest(REALM) do |username| # USERS[username] # end # end # end # # === Notes # # The +authenticate_or_request_with_http_digest+ block must return the user's password # or the ha1 digest hash so the framework can appropriately hash to check the user's # credentials. Returning +nil+ will cause authentication to fail. # # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If # the password file or database is compromised, the attacker would be able to use the ha1 hash to # authenticate as the user at this +realm+, but would not have the user's password to try using at # other sites. # # In rare instances, web servers or front proxies strip authorization headers before # they reach your application. You can debug this situation by logging all environment # variables, and check for HTTP_AUTHORIZATION, amongst others. module Digest extend ::ActionController::HttpAuthentication::Digest module ControllerMethods def authenticate_or_request_with_http_digest: (?::String realm, ?untyped? message) { () -> untyped } -> untyped # Authenticate with HTTP Digest, returns true or false def authenticate_with_http_digest: (?::String realm) { () -> untyped } -> untyped # Render output including the HTTP Digest authentication header def request_http_digest_authentication: (?::String realm, ?untyped? message) -> untyped end # Returns false on a valid response, true otherwise def authenticate: (untyped request, untyped realm) { () -> untyped } -> untyped # Returns false unless the request credentials response value matches the expected value. # First try the password as a ha1 digest password. If this fails, then try it as a plain # text password. def validate_digest_response: (untyped request, untyped realm) { () -> untyped } -> (::FalseClass | untyped) # Returns the expected response for a request of +http_method+ to +uri+ with the decoded +credentials+ and the expected +password+ # Optional parameter +password_is_ha1+ is set to +true+ by default, since best practice is to store ha1 digest instead # of a plain-text password. def expected_response: (untyped http_method, untyped uri, untyped credentials, untyped password, ?bool password_is_ha1) -> untyped def ha1: (untyped credentials, untyped password) -> untyped def encode_credentials: (untyped http_method, untyped credentials, untyped password, untyped password_is_ha1) -> untyped def decode_credentials_header: (untyped request) -> untyped def decode_credentials: (untyped header) -> untyped def authentication_header: (untyped controller, untyped realm) -> untyped def authentication_request: (untyped controller, untyped realm, ?untyped? message) -> untyped def secret_token: (untyped request) -> untyped # Uses an MD5 digest based on time to generate a value to be used only once. # # A server-specified data string which should be uniquely generated each time a 401 response is made. # It is recommended that this string be base64 or hexadecimal data. # Specifically, since the string is passed in the header lines as a quoted string, the double-quote character is not allowed. # # The contents of the nonce are implementation dependent. # The quality of the implementation depends on a good choice. # A nonce might, for example, be constructed as the base 64 encoding of # # time-stamp H(time-stamp ":" ETag ":" private-key) # # where time-stamp is a server-generated time or other non-repeating value, # ETag is the value of the HTTP ETag header associated with the requested entity, # and private-key is data known only to the server. # With a nonce of this form a server would recalculate the hash portion after receiving the client authentication header and # reject the request if it did not match the nonce from that header or # if the time-stamp value is not recent enough. In this way the server can limit the time of the nonce's validity. # The inclusion of the ETag prevents a replay request for an updated version of the resource. # (Note: including the IP address of the client in the nonce would appear to offer the server the ability # to limit the reuse of the nonce to the same client that originally got it. # However, that would break proxy farms, where requests from a single user often go through different proxies in the farm. # Also, IP address spoofing is not that hard.) # # An implementation might choose not to accept a previously used nonce or a previously used digest, in order to # protect against a replay attack. Or, an implementation might choose to use one-time nonces or digests for # POST, PUT, or PATCH requests and a time-stamp for GET requests. For more details on the issues involved see Section 4 # of this document. # # The nonce is opaque to the client. Composed of Time, and hash of Time with secret # key from the Rails session secret generated upon creation of project. Ensures # the time cannot be modified by client. def nonce: (untyped secret_key, ?untyped time) -> untyped # Might want a shorter timeout depending on whether the request # is a PATCH, PUT, or POST, and if the client is a browser or web service. # Can be much shorter if the Stale directive is implemented. This would # allow a user to use new nonce without prompting the user again for their # username and password. def validate_nonce: (untyped secret_key, untyped request, untyped value, ?untyped seconds_to_timeout) -> (::FalseClass | untyped) # Opaque based on digest of secret key def opaque: (untyped secret_key) -> untyped end # Makes it dead easy to do HTTP Token authentication. # # Simple Token example: # # class PostsController < ApplicationController # TOKEN = "secret" # # before_action :authenticate, except: [ :index ] # # def index # render plain: "Everyone can see me!" # end # # def edit # render plain: "I'm only accessible if you know the password" # end # # private # def authenticate # authenticate_or_request_with_http_token do |token, options| # # Compare the tokens in a time-constant manner, to mitigate # # timing attacks. # ActiveSupport::SecurityUtils.secure_compare(token, TOKEN) # end # end # end # # # Here is a more advanced Token example where only Atom feeds and the XML API is protected by HTTP token authentication, # the regular HTML interface is protected by a session approach: # # class ApplicationController < ActionController::Base # before_action :set_account, :authenticate # # private # def set_account # @account = Account.find_by(url_name: request.subdomains.first) # end # # def authenticate # case request.format # when Mime[:xml], Mime[:atom] # if user = authenticate_with_http_token { |t, o| @account.users.authenticate(t, o) } # @current_user = user # else # request_http_token_authentication # end # else # if session_authenticated? # @current_user = @account.users.find(session[:authenticated][:user_id]) # else # redirect_to(login_url) and return false # end # end # end # end # # # In your integration tests, you can do something like this: # # def test_access_granted_from_xml # authorization = ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token) # # get "/notes/1.xml", headers: { 'HTTP_AUTHORIZATION' => authorization } # # assert_equal 200, status # end # # # On shared hosts, Apache sometimes doesn't pass authentication headers to # FCGI instances. If your environment matches this description and you cannot # authenticate, try this rule in your Apache setup: # # RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L] module Token TOKEN_KEY: ::String TOKEN_REGEX: untyped AUTHN_PAIR_DELIMITERS: untyped extend ::ActionController::HttpAuthentication::Token module ControllerMethods def authenticate_or_request_with_http_token: (?::String realm, ?untyped? message) { () -> untyped } -> untyped def authenticate_with_http_token: () { () -> untyped } -> untyped def request_http_token_authentication: (?::String realm, ?untyped? message) -> untyped end def authenticate: (untyped controller) { () -> untyped } -> untyped # Parses the token and options out of the token Authorization header. # The value for the Authorization header is expected to have the prefix # "Token" or "Bearer". If the header looks like this: # Authorization: Token token="abc", nonce="def" # Then the returned token is "abc", and the options are # {nonce: "def"} # # request - ActionDispatch::Request instance with the current headers. # # Returns an +Array+ of [String, Hash] if a token is present. # Returns +nil+ if no token is found. def token_and_options: (untyped request) -> untyped def token_params_from: (untyped auth) -> untyped # Takes raw_params and turns it into an array of parameters def params_array_from: (untyped raw_params) -> untyped # This removes the " characters wrapping the value. def rewrite_param_values: (untyped array_params) -> untyped # This method takes an authorization body and splits up the key-value # pairs by the standardized :, ;, or \t # delimiters defined in +AUTHN_PAIR_DELIMITERS+. def raw_params: (untyped auth) -> untyped # Encodes the given token and options into an Authorization header value. # # token - String token. # options - optional Hash of the options. # # Returns String. def encode_credentials: (untyped token, ?::Hash[untyped, untyped] options) -> ::String # Sets a WWW-Authenticate header to let the client know a token is desired. # # controller - ActionController::Base instance for the outgoing response. # realm - String realm to use in the header. # # Returns nothing. def authentication_request: (untyped controller, untyped realm, ?untyped? message) -> untyped end end end module ActionController # Handles implicit rendering for a controller action that does not # explicitly respond with +render+, +respond_to+, +redirect+, or +head+. # # For API controllers, the implicit response is always 204 No Content. # # For all other controllers, we use these heuristics to decide whether to # render a template, raise an error for a missing template, or respond with # 204 No Content: # # First, if we DO find a template, it's rendered. Template lookup accounts # for the action name, locales, format, variant, template handlers, and more # (see +render+ for details). # # Second, if we DON'T find a template but the controller action does have # templates for other formats, variants, etc., then we trust that you meant # to provide a template for this response, too, and we raise # ActionController::UnknownFormat with an explanation. # # Third, if we DON'T find a template AND the request is a page load in a web # browser (technically, a non-XHR GET request for an HTML response) where # you reasonably expect to have rendered a template, then we raise # ActionView::UnknownFormat with an explanation. # # Finally, if we DON'T find a template AND the request isn't a browser page # load, then we implicitly respond with 204 No Content. module ImplicitRender # :stopdoc: include BasicImplicitRender def default_render: () -> untyped def method_for_action: (untyped action_name) -> untyped private def interactive_browser_request?: () -> untyped end end module ActionController # Adds instrumentation to several ends in ActionController::Base. It also provides # some hooks related with process_action. This allows an ORM like Active Record # and/or DataMapper to plug in ActionController and show related information. # # Check ActiveRecord::Railties::ControllerRuntime for an example. module Instrumentation extend ActiveSupport::Concern include AbstractController::Logger attr_accessor view_runtime(@_view_runtime): untyped def process_action: (*untyped args) -> untyped def render: (*untyped args) -> untyped def send_file: (untyped path, ?::Hash[untyped, untyped] options) -> untyped def send_data: (untyped data, ?::Hash[untyped, untyped] options) -> untyped def redirect_to: (*untyped args) -> untyped private # A hook invoked every time a before callback is halted. def halted_callback_hook: (untyped filter) -> untyped def cleanup_view_runtime: () { () -> untyped } -> untyped def append_info_to_payload: (untyped payload) -> untyped module ClassMethods def log_process_action: (untyped payload) -> untyped end end end module ActionController # Mix this module into your controller, and all actions in that controller # will be able to stream data to the client as it's written. # # class MyController < ActionController::Base # include ActionController::Live # # def stream # response.headers['Content-Type'] = 'text/event-stream' # 100.times { # response.stream.write "hello world\n" # sleep 1 # } # ensure # response.stream.close # end # end # # There are a few caveats with this module. You *cannot* write headers after the # response has been committed (Response#committed? will return truthy). # Calling +write+ or +close+ on the response stream will cause the response # object to be committed. Make sure all headers are set before calling write # or close on your stream. # # You *must* call close on your stream when you're finished, otherwise the # socket may be left open forever. # # The final caveat is that your actions are executed in a separate thread than # the main thread. Make sure your actions are thread safe, and this shouldn't # be a problem (don't share state across threads, etc). module Live extend ActiveSupport::Concern module ClassMethods def make_response!: (untyped request) -> untyped end # This class provides the ability to write an SSE (Server Sent Event) # to an IO stream. The class is initialized with a stream and can be used # to either write a JSON string or an object which can be converted to JSON. # # Writing an object will convert it into standard SSE format with whatever # options you have configured. You may choose to set the following options: # # 1) Event. If specified, an event with this name will be dispatched on # the browser. # 2) Retry. The reconnection time in milliseconds used when attempting # to send the event. # 3) Id. If the connection dies while sending an SSE to the browser, then # the server will receive a +Last-Event-ID+ header with value equal to +id+. # # After setting an option in the constructor of the SSE object, all future # SSEs sent across the stream will use those options unless overridden. # # Example Usage: # # class MyController < ActionController::Base # include ActionController::Live # # def index # response.headers['Content-Type'] = 'text/event-stream' # sse = SSE.new(response.stream, retry: 300, event: "event-name") # sse.write({ name: 'John'}) # sse.write({ name: 'John'}, id: 10) # sse.write({ name: 'John'}, id: 10, event: "other-event") # sse.write({ name: 'John'}, id: 10, event: "other-event", retry: 500) # ensure # sse.close # end # end # # Note: SSEs are not currently supported by IE. However, they are supported # by Chrome, Firefox, Opera, and Safari. class SSE PERMITTED_OPTIONS: ::Array[untyped] def initialize: (untyped stream, ?::Hash[untyped, untyped] options) -> untyped def close: () -> untyped def write: (untyped object, ?::Hash[untyped, untyped] options) -> untyped private def perform_write: (untyped json, untyped options) -> untyped end class ClientDisconnected < RuntimeError end class Buffer < ActionDispatch::Response::Buffer # nodoc: include MonitorMixin # Ignore that the client has disconnected. # # If this value is `true`, calling `write` after the client # disconnects will result in the written content being silently # discarded. If this value is `false` (the default), a # ClientDisconnected exception will be raised. attr_accessor ignore_disconnect: untyped def initialize: (untyped response) -> untyped def write: (untyped string) -> untyped # Write a 'close' event to the buffer; the producer/writing thread # uses this to notify us that it's finished supplying content. # # See also #abort. def close: () -> untyped # Inform the producer/writing thread that the client has # disconnected; the reading thread is no longer interested in # anything that's being written. # # See also #close. def abort: () -> untyped # Is the client still connected and waiting for content? # # The result of calling `write` when this is `false` is determined # by `ignore_disconnect`. def connected?: () -> untyped def on_error: () { () -> untyped } -> untyped def call_on_error: () -> untyped private def each_chunk: () { (untyped) -> untyped } -> untyped end class Response < ActionDispatch::Response private def before_committed: () -> untyped def build_buffer: (untyped response, untyped body) -> untyped end def process: (untyped name) -> untyped def response_body=: (untyped body) -> untyped private def new_controller_thread: () { () -> untyped } -> untyped def log_error: (untyped exception) -> (nil | untyped) end end module ActionController # nodoc: module MimeResponds # Without web-service support, an action which collects the data for displaying a list of people # might look something like this: # # def index # @people = Person.all # end # # That action implicitly responds to all formats, but formats can also be explicitly enumerated: # # def index # @people = Person.all # respond_to :html, :js # end # # Here's the same action, with web-service support baked in: # # def index # @people = Person.all # # respond_to do |format| # format.html # format.js # format.xml { render xml: @people } # end # end # # What that says is, "if the client wants HTML or JS in response to this action, just respond as we # would have before, but if the client wants XML, return them the list of people in XML format." # (Rails determines the desired response format from the HTTP Accept header submitted by the client.) # # Supposing you have an action that adds a new person, optionally creating their company # (by name) if it does not already exist, without web-services, it might look like this: # # def create # @company = Company.find_or_create_by(name: params[:company][:name]) # @person = @company.people.create(params[:person]) # # redirect_to(person_list_url) # end # # Here's the same action, with web-service support baked in: # # def create # company = params[:person].delete(:company) # @company = Company.find_or_create_by(name: company[:name]) # @person = @company.people.create(params[:person]) # # respond_to do |format| # format.html { redirect_to(person_list_url) } # format.js # format.xml { render xml: @person.to_xml(include: @company) } # end # end # # If the client wants HTML, we just redirect them back to the person list. If they want JavaScript, # then it is an Ajax request and we render the JavaScript template associated with this action. # Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also # include the person's company in the rendered XML, so you get something like this: # #