aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller.rb3
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb423
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb138
-rw-r--r--actionpack/lib/abstract_controller/view_paths.rb96
-rw-r--r--actionpack/lib/action_controller.rb10
-rw-r--r--actionpack/lib/action_controller/base.rb18
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb42
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb38
-rw-r--r--actionpack/lib/action_controller/railtie.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb34
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (renamed from actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb)0
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb23
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (renamed from actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb)0
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb15
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb (renamed from actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb)0
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb (renamed from actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb)0
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb11
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb (renamed from actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb)0
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb8
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb (renamed from actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb)0
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb3
22 files changed, 170 insertions, 696 deletions
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 867a7954e0..fe9802e395 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -10,12 +10,11 @@ module AbstractController
autoload :Base
autoload :Callbacks
autoload :Collector
+ autoload :DoubleRenderError, "abstract_controller/rendering"
autoload :Helpers
- autoload :Layouts
autoload :Logger
autoload :Rendering
autoload :Translation
autoload :AssetPaths
- autoload :ViewPaths
autoload :UrlFor
end
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
deleted file mode 100644
index 8e7bdf620e..0000000000
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ /dev/null
@@ -1,423 +0,0 @@
-require "active_support/core_ext/module/remove_method"
-
-module AbstractController
- # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
- # repeated setups. The inclusion pattern has pages that look like this:
- #
- # <%= render "shared/header" %>
- # Hello World
- # <%= render "shared/footer" %>
- #
- # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose
- # and if you ever want to change the structure of these two includes, you'll have to change all the templates.
- #
- # With layouts, you can flip it around and have the common structure know where to insert changing content. This means
- # that the header and footer are only mentioned in one place, like this:
- #
- # // The header part of this layout
- # <%= yield %>
- # // The footer part of this layout
- #
- # And then you have content pages that look like this:
- #
- # hello world
- #
- # At rendering time, the content page is computed and then inserted in the layout, like this:
- #
- # // The header part of this layout
- # hello world
- # // The footer part of this layout
- #
- # == Accessing shared variables
- #
- # Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with
- # references that won't materialize before rendering time:
- #
- # <h1><%= @page_title %></h1>
- # <%= yield %>
- #
- # ...and content pages that fulfill these references _at_ rendering time:
- #
- # <% @page_title = "Welcome" %>
- # Off-world colonies offers you a chance to start a new life
- #
- # The result after rendering is:
- #
- # <h1>Welcome</h1>
- # Off-world colonies offers you a chance to start a new life
- #
- # == Layout assignment
- #
- # You can either specify a layout declaratively (using the #layout class method) or give
- # it the same name as your controller, and place it in <tt>app/views/layouts</tt>.
- # If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance.
- #
- # For instance, if you have PostsController and a template named <tt>app/views/layouts/posts.html.erb</tt>,
- # that template will be used for all actions in PostsController and controllers inheriting
- # from PostsController.
- #
- # If you use a module, for instance Weblog::PostsController, you will need a template named
- # <tt>app/views/layouts/weblog/posts.html.erb</tt>.
- #
- # Since all your controllers inherit from ApplicationController, they will use
- # <tt>app/views/layouts/application.html.erb</tt> if no other layout is specified
- # or provided.
- #
- # == Inheritance Examples
- #
- # class BankController < ActionController::Base
- # # bank.html.erb exists
- #
- # class ExchangeController < BankController
- # # exchange.html.erb exists
- #
- # class CurrencyController < BankController
- #
- # class InformationController < BankController
- # layout "information"
- #
- # class TellerController < InformationController
- # # teller.html.erb exists
- #
- # class EmployeeController < InformationController
- # # employee.html.erb exists
- # layout nil
- #
- # class VaultController < BankController
- # layout :access_level_layout
- #
- # class TillController < BankController
- # layout false
- #
- # In these examples, we have three implicit lookup scenarios:
- # * The BankController uses the "bank" layout.
- # * The ExchangeController uses the "exchange" layout.
- # * The CurrencyController inherits the layout from BankController.
- #
- # However, when a layout is explicitly set, the explicitly set layout wins:
- # * The InformationController uses the "information" layout, explicitly set.
- # * The TellerController also uses the "information" layout, because the parent explicitly set it.
- # * The EmployeeController uses the "employee" layout, because it set the layout to nil, resetting the parent configuration.
- # * The VaultController chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
- # * The TillController does not use a layout at all.
- #
- # == Types of layouts
- #
- # Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes
- # you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can
- # be done either by specifying a method reference as a symbol or using an inline method (as a proc).
- #
- # The method reference is the preferred approach to variable layouts and is used like this:
- #
- # class WeblogController < ActionController::Base
- # layout :writers_and_readers
- #
- # def index
- # # fetching posts
- # end
- #
- # private
- # def writers_and_readers
- # logged_in? ? "writer_layout" : "reader_layout"
- # end
- # end
- #
- # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing
- # is logged in or not.
- #
- # If you want to use an inline method, such as a proc, do something like this:
- #
- # class WeblogController < ActionController::Base
- # layout proc { |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }
- # end
- #
- # If an argument isn't given to the proc, it's evaluated in the context of
- # the current controller anyway.
- #
- # class WeblogController < ActionController::Base
- # layout proc { logged_in? ? "writer_layout" : "reader_layout" }
- # end
- #
- # Of course, the most common way of specifying a layout is still just as a plain template name:
- #
- # class WeblogController < ActionController::Base
- # layout "weblog_standard"
- # end
- #
- # The template will be looked always in <tt>app/views/layouts/</tt> folder. But you can point
- # <tt>layouts</tt> folder direct also. <tt>layout "layouts/demo"</tt> is the same as <tt>layout "demo"</tt>.
- #
- # Setting the layout to nil forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists.
- # Setting it to nil is useful to re-enable template lookup overriding a previous configuration set in the parent:
- #
- # class ApplicationController < ActionController::Base
- # layout "application"
- # end
- #
- # class PostsController < ApplicationController
- # # Will use "application" layout
- # end
- #
- # class CommentsController < ApplicationController
- # # Will search for "comments" layout and fallback "application" layout
- # layout nil
- # end
- #
- # == Conditional layouts
- #
- # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering
- # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The
- # <tt>:only</tt> and <tt>:except</tt> options can be passed to the layout call. For example:
- #
- # class WeblogController < ActionController::Base
- # layout "weblog_standard", except: :rss
- #
- # # ...
- #
- # end
- #
- # This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will
- # be rendered directly, without wrapping a layout around the rendered view.
- #
- # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
- # #<tt>except: [ :rss, :text_only ]</tt> is valid, as is <tt>except: :rss</tt>.
- #
- # == Using a different layout in the action render call
- #
- # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above.
- # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller.
- # You can do this by passing a <tt>:layout</tt> option to the <tt>render</tt> call. For example:
- #
- # class WeblogController < ActionController::Base
- # layout "weblog_standard"
- #
- # def help
- # render action: "help", layout: "help"
- # end
- # end
- #
- # This will override the controller-wide "weblog_standard" layout, and will render the help action with the "help" layout instead.
- module Layouts
- extend ActiveSupport::Concern
-
- include Rendering
-
- included do
- class_attribute :_layout, :_layout_conditions, :instance_accessor => false
- self._layout = nil
- self._layout_conditions = {}
- _write_layout_method
- end
-
- delegate :_layout_conditions, to: :class
-
- module ClassMethods
- def inherited(klass) # :nodoc:
- super
- klass._write_layout_method
- end
-
- # This module is mixed in if layout conditions are provided. This means
- # that if no layout conditions are used, this method is not used
- module LayoutConditions # :nodoc:
- private
-
- # Determines whether the current action has a layout definition by
- # checking the action name against the :only and :except conditions
- # set by the <tt>layout</tt> method.
- #
- # ==== Returns
- # * <tt> Boolean</tt> - True if the action has a layout definition, false otherwise.
- def _conditional_layout?
- return unless super
-
- conditions = _layout_conditions
-
- if only = conditions[:only]
- only.include?(action_name)
- elsif except = conditions[:except]
- !except.include?(action_name)
- else
- true
- end
- end
- end
-
- # Specify the layout to use for this class.
- #
- # If the specified layout is a:
- # String:: the String is the template name
- # Symbol:: call the method specified by the symbol, which will return the template name
- # false:: There is no layout
- # true:: raise an ArgumentError
- # nil:: Force default layout behavior with inheritance
- #
- # ==== Parameters
- # * <tt>layout</tt> - The layout to use.
- #
- # ==== Options (conditions)
- # * :only - A list of actions to apply this layout to.
- # * :except - Apply this layout to all actions but this one.
- def layout(layout, conditions = {})
- include LayoutConditions unless conditions.empty?
-
- conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
- self._layout_conditions = conditions
-
- self._layout = layout
- _write_layout_method
- end
-
- # If no layout is supplied, look for a template named the return
- # value of this method.
- #
- # ==== Returns
- # * <tt>String</tt> - A template name
- def _implied_layout_name # :nodoc:
- controller_path
- end
-
- # Creates a _layout method to be called by _default_layout .
- #
- # If a layout is not explicitly mentioned then look for a layout with the controller's name.
- # if nothing is found then try same procedure to find super class's layout.
- def _write_layout_method # :nodoc:
- remove_possible_method(:_layout)
-
- prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
- default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}).first || super"
- name_clause = if name
- default_behavior
- else
- <<-RUBY
- super
- RUBY
- end
-
- layout_definition = case _layout
- when String
- _layout.inspect
- when Symbol
- <<-RUBY
- #{_layout}.tap do |layout|
- return #{default_behavior} if layout.nil?
- unless layout.is_a?(String) || !layout
- raise ArgumentError, "Your layout method :#{_layout} returned \#{layout}. It " \
- "should have returned a String, false, or nil"
- end
- end
- RUBY
- when Proc
- define_method :_layout_from_proc, &_layout
- protected :_layout_from_proc
- <<-RUBY
- result = _layout_from_proc(#{_layout.arity == 0 ? '' : 'self'})
- return #{default_behavior} if result.nil?
- result
- RUBY
- when false
- nil
- when true
- raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil"
- when nil
- name_clause
- end
-
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def _layout
- if _conditional_layout?
- #{layout_definition}
- else
- #{name_clause}
- end
- end
- private :_layout
- RUBY
- end
- end
-
- def _normalize_options(options) # :nodoc:
- super
-
- if _include_layout?(options)
- layout = options.delete(:layout) { :default }
- options[:layout] = _layout_for_option(layout)
- end
- end
-
- attr_internal_writer :action_has_layout
-
- def initialize(*) # :nodoc:
- @_action_has_layout = true
- super
- end
-
- # Controls whether an action should be rendered using a layout.
- # If you want to disable any <tt>layout</tt> settings for the
- # current action so that it is rendered without a layout then
- # either override this method in your controller to return false
- # for that action or set the <tt>action_has_layout</tt> attribute
- # to false before rendering.
- def action_has_layout?
- @_action_has_layout
- end
-
- private
-
- def _conditional_layout?
- true
- end
-
- # This will be overwritten by _write_layout_method
- def _layout; end
-
- # Determine the layout for a given name, taking into account the name type.
- #
- # ==== Parameters
- # * <tt>name</tt> - The name of the template
- def _layout_for_option(name)
- case name
- when String then _normalize_layout(name)
- when Proc then name
- when true then Proc.new { _default_layout(true) }
- when :default then Proc.new { _default_layout(false) }
- when false, nil then nil
- else
- raise ArgumentError,
- "String, Proc, :default, true, or false, expected for `layout'; you passed #{name.inspect}"
- end
- end
-
- def _normalize_layout(value)
- value.is_a?(String) && value !~ /\blayouts/ ? "layouts/#{value}" : value
- end
-
- # Returns the default layout for this controller.
- # Optionally raises an exception if the layout could not be found.
- #
- # ==== Parameters
- # * <tt>require_layout</tt> - If set to true and layout is not found,
- # an ArgumentError exception is raised (defaults to false)
- #
- # ==== Returns
- # * <tt>template</tt> - The template object for the default layout (or nil)
- def _default_layout(require_layout = false)
- begin
- value = _layout if action_has_layout?
- rescue NameError => e
- raise e, "Could not render layout: #{e.message}"
- end
-
- if require_layout && action_has_layout? && !value
- raise ArgumentError,
- "There was no default layout for #{self.class} in #{view_paths.inspect}"
- end
-
- _normalize_layout(value)
- end
-
- def _include_layout?(options)
- (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
- end
- end
-end
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 3f34add790..5a5c47eb3b 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -1,5 +1,5 @@
-require "abstract_controller/base"
-require "action_view"
+require 'active_support/concern'
+require 'active_support/core_ext/class/attribute'
module AbstractController
class DoubleRenderError < Error
@@ -10,91 +10,16 @@ module AbstractController
end
end
- # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
- # it will trigger the lookup_context and consequently expire the cache.
- class I18nProxy < ::I18n::Config #:nodoc:
- attr_reader :original_config, :lookup_context
-
- def initialize(original_config, lookup_context)
- original_config = original_config.original_config if original_config.respond_to?(:original_config)
- @original_config, @lookup_context = original_config, lookup_context
- end
-
- def locale
- @original_config.locale
- end
-
- def locale=(value)
- @lookup_context.locale = value
- end
- end
-
module Rendering
extend ActiveSupport::Concern
- include AbstractController::ViewPaths
included do
class_attribute :protected_instance_variables
self.protected_instance_variables = []
end
- # Overwrite process to setup I18n proxy.
- def process(*) #:nodoc:
- old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
- super
- ensure
- I18n.config = old_config
- end
-
- module ClassMethods
- def view_context_class
- @view_context_class ||= begin
- routes = respond_to?(:_routes) && _routes
- helpers = respond_to?(:_helpers) && _helpers
-
- Class.new(ActionView::Base) do
- if routes
- include routes.url_helpers
- include routes.mounted_helpers
- end
-
- if helpers
- include helpers
- end
- end
- end
- end
- end
-
- attr_internal_writer :view_context_class
-
- def view_context_class
- @_view_context_class ||= self.class.view_context_class
- end
-
- # An instance of a view class. The default view class is ActionView::Base
- #
- # The view class must have the following methods:
- # View.new[lookup_context, assigns, controller]
- # Create a new ActionView instance for a controller
- # View#render[options]
- # Returns String with the rendered template
- #
- # Override this method in a module to change the default behavior.
- def view_context
- view_context_class.new(view_renderer, view_assigns, self)
- end
-
- # Returns an object that is able to render templates.
- def view_renderer
- @_view_renderer ||= ActionView::Renderer.new(lookup_context)
- end
-
- # Normalize arguments, options and then delegates render_to_body and
- # sticks the result in self.response_body.
- def render(*args, &block)
- options = _normalize_render(*args, &block)
- self.response_body = render_to_body(options)
+ def default_protected_instance_vars
+ [:@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config]
end
# Raw rendering of a template to a string.
@@ -109,28 +34,23 @@ module AbstractController
# overridden in order to still return a string.
# :api: plugin
def render_to_string(*args, &block)
- options = _normalize_render(*args, &block)
- render_to_body(options)
end
# Raw rendering of a template.
# :api: plugin
def render_to_body(options = {})
- _process_options(options)
- _render_template(options)
end
- # Find and renders a template based on the options given.
- # :api: private
- def _render_template(options) #:nodoc:
- lookup_context.rendered_format = nil if options[:formats]
- view_renderer.render(view_context, options)
+ # Normalize arguments, options and then delegates render_to_body and
+ # sticks the result in self.response_body.
+ # :api: public
+ def render(*args, &block)
end
- DEFAULT_PROTECTED_INSTANCE_VARIABLES = [
- :@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config,
- :@_view_context_class, :@_view_renderer, :@_lookup_context
- ]
+ # Return Content-Type of rendered content
+ # :api: public
+ def rendered_format
+ end
# This method should return a hash with assigns.
# You can overwrite this configuration per controller.
@@ -139,58 +59,28 @@ module AbstractController
hash = {}
variables = instance_variables
variables -= protected_instance_variables
- variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES
+ variables -= default_protected_instance_vars
variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) }
hash
end
- private
-
- # Normalize args and options.
- # :api: private
- def _normalize_render(*args, &block)
- options = _normalize_args(*args, &block)
- _normalize_options(options)
- options
- end
-
# Normalize args by converting render "foo" to render :action => "foo" and
# render "foo/bar" to render :file => "foo/bar".
# :api: plugin
def _normalize_args(action=nil, options={})
- case action
- when NilClass
- when Hash
- options = action
- when String, Symbol
- action = action.to_s
- key = action.include?(?/) ? :file : :action
- options[key] = action
- else
- options[:partial] = action
- end
-
options
end
# Normalize options.
# :api: plugin
def _normalize_options(options)
- if options[:partial] == true
- options[:partial] = action_name
- end
-
- if (options.keys & [:partial, :file, :template]).empty?
- options[:prefixes] ||= _prefixes
- end
-
- options[:template] ||= (options[:action] || action_name).to_s
options
end
# Process extra options.
# :api: plugin
def _process_options(options)
+ options
end
end
end
diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb
deleted file mode 100644
index c08b3a0e2a..0000000000
--- a/actionpack/lib/abstract_controller/view_paths.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-require 'action_view/base'
-
-module AbstractController
- module ViewPaths
- extend ActiveSupport::Concern
-
- included do
- class_attribute :_view_paths
- self._view_paths = ActionView::PathSet.new
- self._view_paths.freeze
- end
-
- delegate :template_exists?, :view_paths, :formats, :formats=,
- :locale, :locale=, :to => :lookup_context
-
- module ClassMethods
- def parent_prefixes
- @parent_prefixes ||= begin
- parent_controller = superclass
- prefixes = []
-
- until parent_controller.abstract?
- prefixes << parent_controller.controller_path
- parent_controller = parent_controller.superclass
- end
-
- prefixes
- end
- end
- end
-
- # The prefixes used in render "foo" shortcuts.
- def _prefixes
- @_prefixes ||= begin
- parent_prefixes = self.class.parent_prefixes
- parent_prefixes.dup.unshift(controller_path)
- end
- end
-
- # LookupContext is the object responsible to hold all information required to lookup
- # templates, i.e. view paths and details. Check ActionView::LookupContext for more
- # information.
- def lookup_context
- @_lookup_context ||=
- ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes)
- end
-
- def details_for_lookup
- { }
- end
-
- def append_view_path(path)
- lookup_context.view_paths.push(*path)
- end
-
- def prepend_view_path(path)
- lookup_context.view_paths.unshift(*path)
- end
-
- module ClassMethods
- # Append a path to the list of view paths for this controller.
- #
- # ==== Parameters
- # * <tt>path</tt> - If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
- # (see ActionView::PathSet for more information)
- def append_view_path(path)
- self._view_paths = view_paths + Array(path)
- end
-
- # Prepend a path to the list of view paths for this controller.
- #
- # ==== Parameters
- # * <tt>path</tt> - If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
- # (see ActionView::PathSet for more information)
- def prepend_view_path(path)
- self._view_paths = ActionView::PathSet.new(Array(path) + view_paths)
- end
-
- # A list of all of the default view paths for this controller.
- def view_paths
- _view_paths
- end
-
- # Set the view paths.
- #
- # ==== Parameters
- # * <tt>paths</tt> - If a PathSet is provided, use that;
- # otherwise, process the parameter into a PathSet.
- def view_paths=(paths)
- self._view_paths = ActionView::PathSet.new(Array(paths))
- end
- end
- end
-end
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index cc03da4904..d6b1908ccb 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -13,6 +13,7 @@ module ActionController
autoload :Middleware
autoload_under "metal" do
+ autoload :BasicRendering, 'action_controller/metal/rendering'
autoload :Compatibility
autoload :ConditionalGet
autoload :Cookies
@@ -46,18 +47,9 @@ module ActionController
def self.eager_load!
super
ActionController::Caching.eager_load!
- HTML.eager_load!
end
end
-# All of these simply register additional autoloads
-require 'action_view'
-require 'action_view/vendor/html-scanner'
-
-ActiveSupport.on_load(:action_view) do
- ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
-end
-
# Common Active Support usage in Action Controller
require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/load_error'
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 67d261db77..9941c06201 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -2,6 +2,21 @@ require "action_controller/log_subscriber"
require "action_controller/metal/params_wrapper"
module ActionController
+ # The <tt>metal</tt> anonymous class was introduced to solve issue with including modules in <tt>ActionController::Base</tt>.
+ # Modules needes to be included in particluar order. First wee need to have <tt>AbstractController::Rendering</tt> included,
+ # next we should include actuall implementation which would be for example <tt>ActionView::Rendering</tt> and after that
+ # <tt>ActionController::Rendering</tt>. This order must be preserved and as we want to have middle module included dynamicaly
+ # <tt>metal</tt> class was introduced. It has <tt>AbstractController::Rendering</tt> included and is parent class of
+ # <tt>ActionController::Base</tt> which includes <tt>ActionController::Rendering</tt>. If we include <tt>ActionView::Rendering</tt>
+ # beetween them to perserve the required order, we can simply do this by:
+ #
+ # ActionController::Base.superclass.send(:include, ActionView::Rendering)
+ #
+ metal = Class.new(Metal) do
+ include AbstractController::Rendering
+ include ActionController::BasicRendering
+ end
+
# 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.
@@ -160,7 +175,7 @@ module ActionController
# render action: "overthere" # won't be called if monkeys is nil
# end
#
- class Base < Metal
+ class Base < metal
abstract!
# We document the request and response methods here because albeit they are
@@ -200,7 +215,6 @@ module ActionController
end
MODULES = [
- AbstractController::Layouts,
AbstractController::Translation,
AbstractController::AssetPaths,
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index bea6b88f91..21224b9c3b 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -1,8 +1,38 @@
module ActionController
- module Rendering
+ # Basic rendering implements the most minimal rendering layer.
+ # It only supports rendering :text and :nothing. Passing any other option will
+ # result in `UnsupportedOperationError` exception. For more functionality like
+ # different formats, layouts etc. you should use `ActionView` gem.
+ module BasicRendering
extend ActiveSupport::Concern
- include AbstractController::Rendering
+ # Render text or nothing (empty string) to response_body
+ # :api: public
+ def render(*args, &block)
+ super(*args, &block)
+ opts = args.first
+ if opts.has_key?(:text) && opts[:text].present?
+ self.response_body = opts[:text]
+ elsif opts.has_key?(:nothing) && opts[:nothing]
+ self.response_body = " "
+ else
+ raise UnsupportedOperationError
+ end
+ end
+
+ def rendered_format
+ Mime::TEXT
+ end
+
+ class UnsupportedOperationError < StandardError
+ def initialize
+ super "Unsupported render operation. BasicRendering supports only :text and :nothing options. For more, you need to include ActionView."
+ end
+ end
+ end
+
+ module Rendering
+ extend ActiveSupport::Concern
# Before processing, set the request formats in current controller formats.
def process_action(*) #:nodoc:
@@ -12,17 +42,17 @@ module ActionController
# Check for double render errors and set the content_type after rendering.
def render(*args) #:nodoc:
- raise ::AbstractController::DoubleRenderError if response_body
+ raise ::AbstractController::DoubleRenderError if self.response_body
super
- self.content_type ||= Mime[lookup_context.rendered_format].to_s
- response_body
+ self.content_type ||= rendered_format.to_s
+ self.response_body
end
# Overwrite render_to_string because body can now be set to a rack body.
def render_to_string(*)
if self.response_body = super
string = ""
- response_body.each { |r| string << r }
+ self.response_body.each { |r| string << r }
string
end
ensure
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 73e9b5660d..62d5931b45 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -193,31 +193,29 @@ module ActionController #:nodoc:
module Streaming
extend ActiveSupport::Concern
- include AbstractController::Rendering
-
protected
- # Set proper cache control and transfer encoding when streaming
- def _process_options(options) #:nodoc:
- super
- if options[:stream]
- if env["HTTP_VERSION"] == "HTTP/1.0"
- options.delete(:stream)
- else
- headers["Cache-Control"] ||= "no-cache"
- headers["Transfer-Encoding"] = "chunked"
- headers.delete("Content-Length")
+ # Set proper cache control and transfer encoding when streaming
+ def _process_options(options) #:nodoc:
+ super
+ if options[:stream]
+ if env["HTTP_VERSION"] == "HTTP/1.0"
+ options.delete(:stream)
+ else
+ headers["Cache-Control"] ||= "no-cache"
+ headers["Transfer-Encoding"] = "chunked"
+ headers.delete("Content-Length")
+ end
end
end
- end
- # Call render_body if we are streaming instead of usual +render+.
- def _render_template(options) #:nodoc:
- if options.delete(:stream)
- Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
- else
- super
+ # Call render_body if we are streaming instead of usual +render+.
+ def _render_template(options) #:nodoc:
+ if options.delete(:stream)
+ Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
+ else
+ super
+ end
end
- end
end
end
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index 5379547c57..0833e65d23 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -1,7 +1,6 @@
require "rails"
require "action_controller"
require "action_dispatch/railtie"
-require "action_view/railtie"
require "abstract_controller/railties/routes_helpers"
require "action_controller/railties/helpers"
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 64230ff1ae..0ca1a87645 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -34,27 +34,35 @@ module ActionDispatch
log_error(env, wrapper)
if env['action_dispatch.show_detailed_exceptions']
+ request = Request.new(env)
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
- :request => Request.new(env),
- :exception => wrapper.exception,
- :application_trace => wrapper.application_trace,
- :framework_trace => wrapper.framework_trace,
- :full_trace => wrapper.full_trace,
- :routes_inspector => routes_inspector(exception),
- :source_extract => wrapper.source_extract,
- :line_number => wrapper.line_number,
- :file => wrapper.file
+ request: request,
+ exception: wrapper.exception,
+ application_trace: wrapper.application_trace,
+ framework_trace: wrapper.framework_trace,
+ full_trace: wrapper.full_trace,
+ routes_inspector: routes_inspector(exception),
+ source_extract: wrapper.source_extract,
+ line_number: wrapper.line_number,
+ file: wrapper.file
)
file = "rescues/#{wrapper.rescue_template}"
- body = template.render(:template => file, :layout => 'rescues/layout')
- render(wrapper.status_code, body)
+
+ if request.xhr?
+ body = template.render(template: file, layout: false, formats: [:text])
+ format = "text/plain"
+ else
+ body = template.render(template: file, layout: 'rescues/layout')
+ format = "text/html"
+ end
+ render(wrapper.status_code, body, format)
else
raise exception
end
end
- def render(status, body)
- [status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
+ def render(status, body, format)
+ [status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
end
def log_error(env, wrapper)
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
index db219c8fa9..db219c8fa9 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb
new file mode 100644
index 0000000000..396768ecee
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb
@@ -0,0 +1,23 @@
+<%
+ clean_params = @request.filtered_parameters.clone
+ clean_params.delete("action")
+ clean_params.delete("controller")
+
+ request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
+
+ def debug_hash(object)
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
+ end unless self.class.method_defined?(:debug_hash)
+%>
+
+Request parameters
+<%= request_dump %>
+
+Session dump
+<%= debug_hash @request.session %>
+
+Env dump
+<%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %>
+
+Response headers
+<%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
index b181909bff..b181909bff 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb
new file mode 100644
index 0000000000..d4af5c9b06
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb
@@ -0,0 +1,15 @@
+<%
+ traces = { "Application Trace" => @application_trace,
+ "Framework Trace" => @framework_trace,
+ "Full Trace" => @full_trace }
+%>
+
+Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %>
+
+<% traces.each do |name, trace| %>
+<% if trace.any? %>
+<%= name %>
+<%= trace.join("\n") %>
+
+<% end %>
+<% end %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb
index 5c016e544e..5c016e544e 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb
new file mode 100644
index 0000000000..ae62d9eb02
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb
@@ -0,0 +1,3 @@
+Template is missing
+
+<%= @exception.message %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb
index 7e9cedb95e..7e9cedb95e 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb
new file mode 100644
index 0000000000..f6e4dac1f3
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb
@@ -0,0 +1,11 @@
+Routing Error
+
+<%= @exception.message %>
+<% unless @exception.failures.empty? %>
+Failure reasons:
+<% @exception.failures.each do |route, reason| %>
+ - <%= route.inspect.delete('\\') %></code> failed because <%= reason.downcase %>
+<% end %>
+<% end %>
+
+<%= render template: "rescues/_trace", format: :text %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb
index 027a0f5b3e..027a0f5b3e 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb
new file mode 100644
index 0000000000..5da21d9784
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb
@@ -0,0 +1,8 @@
+<% @source_extract = @exception.source_extract(0, :html) %>
+<%= @exception.original_exception.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
+
+Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised:
+<%= @exception.message %>
+<%= @exception.sub_template_message %>
+<%= render template: "rescues/_trace", format: :text %>
+<%= render template: "rescues/_request_and_response", format: :text %>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb
index 259fb2bb3b..259fb2bb3b 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb
new file mode 100644
index 0000000000..83973addcb
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb
@@ -0,0 +1,3 @@
+Unknown action
+
+<%= @exception.message %>