# frozen_string_literal: truerequire"abstract_controller/error"require"active_support/configurable"require"active_support/descendants_tracker"require"active_support/core_ext/module/anonymous"require"active_support/core_ext/module/attr_internal"moduleAbstractController# Raised when a non-existing controller action is triggered.classActionNotFound<StandardErrorattr_reader:controller,:action# :nodoc:definitialize(message=nil,controller=nil,action=nil)# :nodoc:@controller=controller@action=actionsuper(message)endifdefined?(DidYouMean::Correctable)&&defined?(DidYouMean::SpellChecker)includeDidYouMean::Correctable# :nodoc:defcorrections# :nodoc:@corrections||=DidYouMean::SpellChecker.new(dictionary: controller.class.action_methods).correct(action)endendend# = Abstract Controller \Base## 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.classBase### Returns the body of the HTTP response sent by the controller.attr_internal:response_body### Returns the name of the action this controller is processing.attr_internal:action_name### Returns the formats that can be processed by the controller.attr_internal:formatsincludeActiveSupport::ConfigurableextendActiveSupport::DescendantsTrackerclass<<selfattr_reader:abstractalias_method:abstract?,:abstract# Define a controller as abstract. See internal_methods for more# details.defabstract!@abstract=trueenddefinherited(klass)# :nodoc:# Define the abstract ivar on subclasses so that we don't get# uninitialized ivar warningsunlessklass.instance_variable_defined?(:@abstract)klass.instance_variable_set(:@abstract,false)endsuperend# 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)definternal_methodscontroller=selfmethods=[]untilcontroller.abstract?methods+=controller.public_instance_methods(false)controller=controller.superclassendcontroller.public_instance_methods(true)-methodsend# 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# * <tt>Set</tt> - A set of all methods that should be considered actions.defaction_methods@action_methods||=begin# All public instance methods of this class, including ancestors# except for public instance methods of Base and its ancestors.methods=public_instance_methods(true)-internal_methods# Be sure to include shadowed public instance methods of this class.methods.concat(public_instance_methods(false))methods.map!(&:to_s)methods.to_setendend# 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.defclear_action_methods!@action_methods=nilend# 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# * <tt>String</tt>defcontroller_path@controller_path||=name.delete_suffix("Controller").underscoreunlessanonymous?end# Refresh the cached action_methods when a new action_method is added.defmethod_added(name)superclear_action_methods!enddefeager_load!# :nodoc:action_methodsnilendendabstract!# 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# * <tt>self</tt>defprocess(action,*args)@_action_name=action.to_sunlessaction_name=_find_action_name(@_action_name)raiseActionNotFound.new("The action '#{action}' could not be found for #{self.class.name}",self,action)end@_response_body=nilprocess_action(action_name,*args)endruby2_keywords(:process)# Delegates to the class's ::controller_path.defcontroller_pathself.class.controller_pathend# Delegates to the class's ::action_methods.defaction_methodsself.class.action_methodsend# Returns true if a method for the action is available and# can be dispatched, false otherwise.## Notice that <tt>action_methods.include?("foo")</tt> may return# false and <tt>available_action?("foo")</tt> returns true because# this method considers actions that are also available# through other means, for example, implicit render ones.## ==== Parameters# * <tt>action_name</tt> - The name of an action to be testeddefavailable_action?(action_name)_find_action_name(action_name)end# Tests if a response body is set. Used to determine if the# +process_action+ callback needs to be terminated in# AbstractController::Callbacks.defperformed?response_bodyend# 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.defself.supports_path?trueenddefinspect# :nodoc:"#<#{self.class.name}:#{'%#016x'%(object_id<<1)}>"endprivate# Returns true if the name can be considered an action because# it has a method defined in the controller.## ==== Parameters# * <tt>name</tt> - The name of an action to be testeddefaction_method?(name)self.class.action_methods.include?(name)end# 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.defprocess_action(...)send_action(...)end# 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.aliassend_actionsend# 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(*args)action_missing(@_action_name,*args)end# 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# * <tt>action_name</tt> - An action name to find a method name for## ==== Returns# * <tt>string</tt> - The name of the method that handles the action# * false - No valid method name could be found.# Raise +AbstractController::ActionNotFound+.def_find_action_name(action_name)_valid_action_name?(action_name)&&method_for_action(action_name)end# 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# * <tt>action_name</tt> - An action name to find a method name for## ==== Returns# * <tt>string</tt> - The name of the method that handles the action# * <tt>nil</tt> - No method name could be found.defmethod_for_action(action_name)ifaction_method?(action_name)action_nameelsifrespond_to?(:action_missing,true)"_handle_action_missing"endend# Checks if the action name is valid and returns false otherwise.def_valid_action_name?(action_name)!action_name.to_s.include?File::SEPARATORendendend