aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller/base.rb7
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb2
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb2
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb2
-rw-r--r--actionpack/lib/action_controller/metal/etag_with_template_digest.rb8
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb51
-rw-r--r--actionpack/lib/action_controller/renderer.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb49
-rw-r--r--actionpack/lib/action_dispatch/routing.rb8
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb12
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb4
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb32
12 files changed, 106 insertions, 73 deletions
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index d4317399ed..aa06f70433 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -150,6 +150,13 @@ module AbstractController
_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+.
+ def performed?
+ response_body
+ end
+
# 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
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index d63ce9c1c3..3ef8da86fa 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -9,7 +9,7 @@ module AbstractController
included do
define_callbacks :process_action,
- terminator: ->(controller, result_lambda) { result_lambda.call if result_lambda.is_a?(Proc); controller.response_body },
+ terminator: ->(controller, result_lambda) { result_lambda.call if result_lambda.is_a?(Proc); controller.performed? },
skip_after_callbacks_if_terminated: true
end
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index a6fb0dbe1d..4ba2c26949 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -122,7 +122,7 @@ module AbstractController
def _normalize_render(*args, &block)
options = _normalize_args(*args, &block)
#TODO: remove defined? when we restore AP <=> AV dependency
- if defined?(request) && request.variant.present?
+ if defined?(request) && !request.nil? && request.variant.present?
options[:variant] = request.variant
end
_normalize_options(options)
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 480e265e44..e21449f376 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -129,7 +129,7 @@ module ActionController
# * <tt>:etag</tt> Sets a "weak" ETag validator on the response. See the
# +:weak_etag+ option.
# * <tt>:weak_etag</tt> Sets a "weak" ETag validator on the response.
- # requests that set If-None-Match header may return a 304 Not Modified
+ # 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
diff --git a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
index 669cf55bca..75ac996793 100644
--- a/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
+++ b/actionpack/lib/action_controller/metal/etag_with_template_digest.rb
@@ -39,8 +39,14 @@ module ActionController
end
end
+ # 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(options)
- options.fetch(:template) { "#{controller_name}/#{action_name}" }
+ unless options[:template] == false
+ options[:template] || "#{controller_name}/#{action_name}"
+ end
end
def lookup_and_digest_template(template)
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 08049d7af8..b326695ce2 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -58,8 +58,7 @@ module ActionController
# })
#
# permitted = params.require(:person).permit(:name, :age)
- # permitted # => {"name"=>"Francesco", "age"=>22}
- # permitted.class # => ActionController::Parameters
+ # permitted # => <ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
# permitted.permitted? # => true
#
# Person.first.update!(permitted)
@@ -87,7 +86,7 @@ module ActionController
#
# params = ActionController::Parameters.new(a: "123", b: "456")
# params.permit(:c)
- # # => {}
+ # # => <ActionController::Parameters {} permitted: true>
#
# ActionController::Parameters.action_on_unpermitted_parameters = :raise
#
@@ -107,6 +106,8 @@ module ActionController
# params["key"] # => "value"
class Parameters
cattr_accessor :permit_all_parameters, instance_accessor: false
+ self.permit_all_parameters = false
+
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
@@ -255,7 +256,7 @@ module ActionController
# either present or the singleton +false+, returns said value:
#
# ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
- # # => {"name"=>"Francesco"}
+ # # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
#
# Otherwise raises <tt>ActionController::ParameterMissing</tt>:
#
@@ -276,12 +277,12 @@ module ActionController
# returned:
#
# params = ActionController::Parameters.new(user: { ... }, profile: { ... })
- # user_params, profile_params = params.require(:user, :profile)
+ # user_params, profile_params = params.require([:user, :profile])
#
# Otherwise, the method re-raises the first exception found:
#
# params = ActionController::Parameters.new(user: {}, profile: {})
- # user_params, profile_params = params.require(:user, :profile)
+ # user_params, profile_params = params.require([:user, :profile])
# # ActionController::ParameterMissing: param is missing or the value is empty: user
#
# Technically this method can be used to fetch terminal values:
@@ -374,13 +375,13 @@ module ActionController
# })
#
# params.require(:person).permit(:contact)
- # # => {}
+ # # => <ActionController::Parameters {} permitted: true>
#
# params.require(:person).permit(contact: :phone)
- # # => {"contact"=>{"phone"=>"555-1234"}}
+ # # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
#
# params.require(:person).permit(contact: [ :email, :phone ])
- # # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}}
+ # # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
def permit(*filters)
params = self.class.new
@@ -402,7 +403,7 @@ module ActionController
# returns +nil+.
#
# params = ActionController::Parameters.new(person: { name: 'Francesco' })
- # params[:person] # => {"name"=>"Francesco"}
+ # params[:person] # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
# params[:none] # => nil
def [](key)
convert_hashes_to_parameters(key, @parameters[key])
@@ -421,7 +422,7 @@ module ActionController
# is given, then that will be run and its result returned.
#
# params = ActionController::Parameters.new(person: { name: 'Francesco' })
- # params.fetch(:person) # => {"name"=>"Francesco"}
+ # params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
# params.fetch(:none, 'Francesco') # => "Francesco"
# params.fetch(:none) { 'Francesco' } # => "Francesco"
@@ -441,12 +442,12 @@ module ActionController
# Extracts the nested parameter from the given +keys+ by calling +dig+
# at each step. Returns +nil+ if any intermediate step is +nil+.
#
- # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
- # params.dig(:foo, :bar, :baz) # => 1
- # params.dig(:foo, :zot, :xyz) # => nil
+ # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
+ # params.dig(:foo, :bar, :baz) # => 1
+ # params.dig(:foo, :zot, :xyz) # => nil
#
- # params2 = ActionController::Parameters.new(foo: [10, 11, 12])
- # params2.dig(:foo, 1) # => 11
+ # params2 = ActionController::Parameters.new(foo: [10, 11, 12])
+ # params2.dig(:foo, 1) # => 11
def dig(*keys)
convert_value_to_parameters(@parameters.dig(*keys))
end
@@ -457,8 +458,8 @@ module ActionController
# don't exist, returns an empty hash.
#
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
- # params.slice(:a, :b) # => {"a"=>1, "b"=>2}
- # params.slice(:d) # => {}
+ # params.slice(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
+ # params.slice(:d) # => <ActionController::Parameters {} permitted: false>
def slice(*keys)
new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
end
@@ -474,8 +475,8 @@ module ActionController
# filters out the given +keys+.
#
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
- # params.except(:a, :b) # => {"c"=>3}
- # params.except(:d) # => {"a"=>1,"b"=>2,"c"=>3}
+ # params.except(:a, :b) # => <ActionController::Parameters {"c"=>3} permitted: false>
+ # params.except(:d) # => <ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
def except(*keys)
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
end
@@ -483,8 +484,8 @@ module ActionController
# Removes and returns the key/value pairs matching the given keys.
#
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
- # params.extract!(:a, :b) # => {"a"=>1, "b"=>2}
- # params # => {"c"=>3}
+ # params.extract!(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
+ # params # => <ActionController::Parameters {"c"=>3} permitted: false>
def extract!(*keys)
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
end
@@ -494,7 +495,7 @@ module ActionController
#
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
# params.transform_values { |x| x * 2 }
- # # => {"a"=>2, "b"=>4, "c"=>6}
+ # # => <ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
def transform_values(&block)
if block
new_instance_with_inherited_permitted_status(
@@ -577,7 +578,7 @@ module ActionController
# params = ActionController::Parameters.new(a: 1)
# params.permit!
# params.permitted? # => true
- # copy_params = params.dup # => {"a"=>1}
+ # copy_params = params.dup # => <ActionController::Parameters {"a"=>1} permitted: true>
# copy_params.permitted? # => true
def dup
super.tap do |duplicate|
@@ -797,7 +798,7 @@ module ActionController
#
# class PeopleController < ActionController::Base
# # Using "Person.create(params[:person])" would raise an
- # # ActiveModel::ForbiddenAttributes exception because it'd
+ # # ActiveModel::ForbiddenAttributesError exception because it'd
# # be using mass assignment without an explicit permit step.
# # This is the recommended form:
# def create
diff --git a/actionpack/lib/action_controller/renderer.rb b/actionpack/lib/action_controller/renderer.rb
index 5ff4a658ad..a8c8d66682 100644
--- a/actionpack/lib/action_controller/renderer.rb
+++ b/actionpack/lib/action_controller/renderer.rb
@@ -1,7 +1,7 @@
require 'active_support/core_ext/hash/keys'
module ActionController
- # ActionController::Renderer allows to render arbitrary templates
+ # ActionController::Renderer allows you to render arbitrary templates
# without requirement of being in controller actions.
#
# You get a concrete renderer class by invoking ActionController::Base#renderer.
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index ed2edcbe06..b1b3e87934 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -527,34 +527,37 @@ module ActionController
@request.set_header k, @controller.config.relative_url_root
end
- @controller.recycle!
- @controller.dispatch(action, @request, @response)
- @request = @controller.request
- @response = @controller.response
-
- @request.delete_header 'HTTP_COOKIE'
+ begin
+ @controller.recycle!
+ @controller.dispatch(action, @request, @response)
+ ensure
+ @request = @controller.request
+ @response = @controller.response
+
+ @request.delete_header 'HTTP_COOKIE'
+
+ if @request.have_cookie_jar?
+ unless @request.cookie_jar.committed?
+ @request.cookie_jar.write(@response)
+ self.cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
+ end
+ end
+ @response.prepare!
- if @request.have_cookie_jar?
- unless @request.cookie_jar.committed?
- @request.cookie_jar.write(@response)
- self.cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
+ if flash_value = @request.flash.to_session_value
+ @request.session['flash'] = flash_value
+ else
+ @request.session.delete('flash')
end
- end
- @response.prepare!
- if flash_value = @request.flash.to_session_value
- @request.session['flash'] = flash_value
- else
- @request.session.delete('flash')
- end
+ if xhr
+ @request.delete_header 'HTTP_X_REQUESTED_WITH'
+ @request.delete_header 'HTTP_ACCEPT'
+ end
+ @request.query_string = ''
- if xhr
- @request.delete_header 'HTTP_X_REQUESTED_WITH'
- @request.delete_header 'HTTP_ACCEPT'
+ @response.sent!
end
- @request.query_string = ''
-
- @response.sent!
@response
end
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index dd6ac9db9c..61ebd0b8db 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -89,7 +89,7 @@ module ActionDispatch
#
# Example:
#
- # # In routes.rb
+ # # In config/routes.rb
# get '/login' => 'accounts#login', as: 'login'
#
# # With render, redirect_to, tests, etc.
@@ -101,7 +101,7 @@ module ActionDispatch
#
# Use <tt>root</tt> as a shorthand to name a route for the root path "/".
#
- # # In routes.rb
+ # # In config/routes.rb
# root to: 'blogs#index'
#
# # would recognize http://www.example.com/ as
@@ -114,7 +114,7 @@ module ActionDispatch
# Note: when using +controller+, the route is simply named after the
# method you call on the block parameter rather than map.
#
- # # In routes.rb
+ # # In config/routes.rb
# controller :blog do
# get 'blog/show' => :list
# get 'blog/delete' => :delete
@@ -196,7 +196,7 @@ module ActionDispatch
#
# Rails.application.reload_routes!
#
- # This will clear all named routes and reload routes.rb if the file has been modified from
+ # This will clear all named routes and reload config/routes.rb if the file has been modified from
# last load. To absolutely force reloading, use <tt>reload!</tt>.
#
# == Testing Routes
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 8ff3b42a40..e2cf75da3a 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -106,7 +106,7 @@ module ActionDispatch
@ast = ast
@anchor = anchor
@via = via
- @internal = options[:internal]
+ @internal = options.delete(:internal)
path_params = ast.find_all(&:symbol?).map(&:to_sym)
@@ -1062,6 +1062,10 @@ module ActionDispatch
def merge_shallow_scope(parent, child) #:nodoc:
child ? true : false
end
+
+ def merge_to_scope(parent, child)
+ child
+ end
end
# Resource routing allows you to quickly declare all of the common routes
@@ -1582,6 +1586,10 @@ module ActionDispatch
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
end
+ if @scope[:to]
+ options[:to] ||= @scope[:to]
+ end
+
if @scope[:controller] && @scope[:action]
options[:to] ||= "#{@scope[:controller]}##{@scope[:action]}"
end
@@ -2021,7 +2029,7 @@ to this:
class Scope # :nodoc:
OPTIONS = [:path, :shallow_path, :as, :shallow_prefix, :module,
:controller, :action, :path_names, :constraints,
- :shallow, :blocks, :defaults, :via, :format, :options]
+ :shallow, :blocks, :defaults, :via, :format, :options, :to]
RESOURCE_SCOPES = [:resource, :resources]
RESOURCE_METHOD_SCOPES = [:collection, :member, :new]
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index 9934f5547a..3156acf615 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -4,7 +4,7 @@ module ActionDispatch
# given an Active Record model instance. They are to be used in combination with
# ActionController::Resources.
#
- # These methods are useful when you want to generate correct URL or path to a RESTful
+ # These methods are useful when you want to generate the correct URL or path to a RESTful
# resource without having to know the exact type of the record in question.
#
# Nested resources and/or namespaces are also supported, as illustrated in the example:
@@ -79,7 +79,7 @@ module ActionDispatch
# polymorphic_url([blog, post], anchor: 'my_anchor', script_name: "/my_app")
# # => "http://example.com/my_app/blogs/1/posts/1#my_anchor"
#
- # For all of these options, see the documentation for <tt>url_for</tt>.
+ # For all of these options, see the documentation for {url_for}[rdoc-ref:ActionDispatch::Routing::UrlFor].
#
# ==== Functionality
#
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 384254b131..5627e79bb7 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -300,7 +300,7 @@ module ActionDispatch
end
end
- REQUEST_KWARGS = %i(params headers env xhr)
+ REQUEST_KWARGS = %i(params headers env xhr as)
def kwarg_request?(args)
args[0].respond_to?(:keys) && args[0].keys.any? { |k| REQUEST_KWARGS.include?(k) }
end
@@ -317,7 +317,8 @@ module ActionDispatch
params: { id: 1 },
headers: { 'X-Extra-Header' => '123' },
env: { 'action_dispatch.custom' => 'custom' },
- xhr: true
+ xhr: true,
+ as: :json
MSG
end
@@ -326,17 +327,17 @@ module ActionDispatch
request_encoder = RequestEncoder.encoder(as)
if path =~ %r{://}
- location = URI.parse(path)
- https! URI::HTTPS === location if location.scheme
- if url_host = location.host
- default = Rack::Request::DEFAULT_PORTS[location.scheme]
- url_host += ":#{location.port}" if default != location.port
- host! url_host
+ path = build_expanded_path(path, request_encoder) do |location|
+ https! URI::HTTPS === location if location.scheme
+
+ if url_host = location.host
+ default = Rack::Request::DEFAULT_PORTS[location.scheme]
+ url_host += ":#{location.port}" if default != location.port
+ host! url_host
+ end
end
- path = request_encoder.append_format_to location.path
- path = location.query ? "#{path}?#{location.query}" : path
- else
- path = request_encoder.append_format_to path
+ elsif as
+ path = build_expanded_path(path, request_encoder)
end
hostname, port = host.split(':')
@@ -395,6 +396,13 @@ module ActionDispatch
"#{env['rack.url_scheme']}://#{env['SERVER_NAME']}:#{env['SERVER_PORT']}#{path}"
end
+ def build_expanded_path(path, request_encoder)
+ location = URI.parse(path)
+ yield location if block_given?
+ path = request_encoder.append_format_to location.path
+ location.query ? "#{path}?#{location.query}" : path
+ end
+
class RequestEncoder # :nodoc:
@encoders = {}