aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb6
-rw-r--r--actionpack/lib/action_controller/metal/live.rb41
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb4
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb4
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb8
-rw-r--r--actionpack/lib/action_controller/test_case.rb44
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb7
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb50
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/builder.rb6
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/simulator.rb2
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/transition_table.rb14
-rw-r--r--actionpack/lib/action_dispatch/journey/nfa/dot.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/nfa/simulator.rb2
-rw-r--r--actionpack/lib/action_dispatch/journey/nfa/transition_table.rb10
-rw-r--r--actionpack/lib/action_dispatch/journey/path/pattern.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb23
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb73
-rw-r--r--actionpack/lib/action_pack/gem_version.rb15
-rw-r--r--actionpack/lib/action_pack/version.rb11
20 files changed, 226 insertions, 106 deletions
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index e920a33765..b1acca2435 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -54,9 +54,9 @@ module ActionController
end
def deep_munge(event)
- message = "Value for params[:#{event.payload[:keys].join('][:')}] was set"\
- "to nil, because it was one of [], [null] or [null, null, ...]."\
- "Go to http://guides.rubyonrails.org/security.html#unsafe-query-generation"\
+ message = "Value for params[:#{event.payload[:keys].join('][:')}] was set "\
+ "to nil, because it was one of [], [null] or [null, null, ...]. "\
+ "Go to http://guides.rubyonrails.org/security.html#unsafe-query-generation "\
"for more information."\
debug(message)
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index fdf4ef293d..41b997a755 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -107,8 +107,11 @@ module ActionController
end
class Buffer < ActionDispatch::Response::Buffer #:nodoc:
+ include MonitorMixin
+
def initialize(response)
- @error_callback = nil
+ @error_callback = lambda { true }
+ @cv = new_cond
super(response, SizedQueue.new(10))
end
@@ -122,14 +125,25 @@ module ActionController
end
def each
+ @response.sending!
while str = @buf.pop
yield str
end
+ @response.sent!
end
def close
- super
- @buf.push nil
+ synchronize do
+ super
+ @buf.push nil
+ @cv.broadcast
+ end
+ end
+
+ def await_close
+ synchronize do
+ @cv.wait_until { @closed }
+ end
end
def on_error(&block)
@@ -165,12 +179,20 @@ module ActionController
end
end
- def commit!
- headers.freeze
+ private
+
+ def before_committed
super
+ jar = request.cookie_jar
+ # The response can be committed multiple times
+ jar.write self unless committed?
end
- private
+ def before_sending
+ super
+ request.cookie_jar.commit!
+ headers.freeze
+ end
def build_buffer(response, body)
buf = Live::Buffer.new response
@@ -191,6 +213,7 @@ module ActionController
t1 = Thread.current
locals = t1.keys.map { |key| [key, t1[key]] }
+ error = nil
# This processes the action in a child thread. It lets us return the
# response code and headers back up the rack stack, and still process
# the body in parallel with sending data to the client
@@ -205,8 +228,9 @@ module ActionController
begin
super(name)
rescue => e
- @_response.status = 500 unless @_response.committed?
- @_response.status = 400 if e.class == ActionController::BadRequest
+ unless @_response.committed?
+ error = e
+ end
begin
@_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html
@_response.stream.call_on_error
@@ -222,6 +246,7 @@ module ActionController
}
@_response.await_commit
+ raise error if error
end
def log_error(exception)
diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index e1bee9e60c..bdf6e88699 100644
--- a/actionpack/lib/action_controller/metal/rack_delegation.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -5,8 +5,8 @@ module ActionController
module RackDelegation
extend ActiveSupport::Concern
- delegate :headers, :status=, :location=, :content_type=, :no_content_type=,
- :status, :location, :content_type, :no_content_type, :to => "@_response"
+ delegate :headers, :status=, :location=, :content_type=,
+ :status, :location, :content_type, :to => "@_response"
def dispatch(action, request)
set_response!(request)
diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 3c4ef596c7..93e7d6954c 100644
--- a/actionpack/lib/action_controller/metal/rendering.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -45,9 +45,7 @@ module ActionController
def _process_format(format, options = {})
super
- if options[:body]
- self.headers.delete "Content-Type"
- elsif options[:plain]
+ if options[:plain]
self.content_type = Mime::TEXT
else
self.content_type ||= format.to_s
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index c88074d4c6..e3b1f5ae7c 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -68,6 +68,10 @@ module ActionController #:nodoc:
config_accessor :allow_forgery_protection
self.allow_forgery_protection = true if allow_forgery_protection.nil?
+ # Controls whether a CSRF failure logs a warning. On by default.
+ config_accessor :log_warning_on_csrf_failure
+ self.log_warning_on_csrf_failure = true
+
helper_method :form_authenticity_token
helper_method :protect_against_forgery?
end
@@ -193,7 +197,9 @@ module ActionController #:nodoc:
mark_for_same_origin_verification!
if !verified_request?
- logger.warn "Can't verify CSRF token authenticity" if logger
+ if logger && log_warning_on_csrf_failure
+ logger.warn "Can't verify CSRF token authenticity"
+ end
handle_unverified_request
end
end
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 8650b75400..e9166d8747 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -258,6 +258,29 @@ module ActionController
end
end
+ class LiveTestResponse < Live::Response
+ def recycle!
+ @body = nil
+ initialize
+ end
+
+ def body
+ @body ||= super
+ end
+
+ # Was the response successful?
+ alias_method :success?, :successful?
+
+ # Was the URL not found?
+ alias_method :missing?, :not_found?
+
+ # Were we redirected?
+ alias_method :redirect?, :redirection?
+
+ # Was there a server-side error?
+ alias_method :error?, :server_error?
+ end
+
# Methods #destroy and #load! are overridden to avoid calling methods on the
# @store object, which does not exist for the TestSession class.
class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
@@ -572,7 +595,9 @@ module ActionController
@controller.process(name)
if cookies = @request.env['action_dispatch.cookies']
- cookies.write(@response)
+ unless @response.committed?
+ cookies.write(@response)
+ end
end
@response.prepare!
@@ -583,13 +608,14 @@ module ActionController
end
def setup_controller_request_and_response
- @request = build_request
- @response = build_response
- @response.request = @request
-
@controller = nil unless defined? @controller
+ response_klass = TestResponse
+
if klass = self.class.controller_class
+ if klass < ActionController::Live
+ response_klass = LiveTestResponse
+ end
unless @controller
begin
@controller = klass.new
@@ -599,6 +625,10 @@ module ActionController
end
end
+ @request = build_request
+ @response = build_response response_klass
+ @response.request = @request
+
if @controller
@controller.request = @request
@controller.params = {}
@@ -609,8 +639,8 @@ module ActionController
TestRequest.new
end
- def build_response
- TestResponse.new
+ def build_response(klass)
+ klass.new
end
included do
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 1318c62fbe..daa06e96e6 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -152,6 +152,13 @@ module ActionDispatch
Http::Headers.new(@env)
end
+ # Returns a +String+ with the last requested path including their params.
+ #
+ # # get '/foo'
+ # request.original_fullpath # => '/foo'
+ #
+ # # get '/foo?bar'
+ # request.original_fullpath # => '/foo?bar'
def original_fullpath
@original_fullpath ||= (env["ORIGINAL_FULLPATH"] || fullpath)
end
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index f14ca1ea44..3d27ff2b24 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -63,8 +63,6 @@ module ActionDispatch # :nodoc:
# content you're giving them, so we need to send that along.
attr_accessor :charset
- attr_accessor :no_content_type # :nodoc:
-
CONTENT_TYPE = "Content-Type".freeze
SET_COOKIE = "Set-Cookie".freeze
LOCATION = "Location".freeze
@@ -93,7 +91,10 @@ module ActionDispatch # :nodoc:
end
def each(&block)
- @buf.each(&block)
+ @response.sending!
+ x = @buf.each(&block)
+ @response.sent!
+ x
end
def close
@@ -120,6 +121,8 @@ module ActionDispatch # :nodoc:
@blank = false
@cv = new_cond
@committed = false
+ @sending = false
+ @sent = false
@content_type = nil
@charset = nil
@@ -140,17 +143,37 @@ module ActionDispatch # :nodoc:
end
end
+ def await_sent
+ synchronize { @cv.wait_until { @sent } }
+ end
+
def commit!
synchronize do
+ before_committed
@committed = true
@cv.broadcast
end
end
- def committed?
- @committed
+ def sending!
+ synchronize do
+ before_sending
+ @sending = true
+ @cv.broadcast
+ end
+ end
+
+ def sent!
+ synchronize do
+ @sent = true
+ @cv.broadcast
+ end
end
+ def sending?; synchronize { @sending }; end
+ def committed?; synchronize { @committed }; end
+ def sent?; synchronize { @sent }; end
+
# Sets the HTTP status code.
def status=(status)
@status = Rack::Utils.status_code(status)
@@ -275,6 +298,12 @@ module ActionDispatch # :nodoc:
private
+ def before_committed
+ end
+
+ def before_sending
+ end
+
def merge_default_headers(original, default)
return original unless default.respond_to?(:merge)
@@ -305,17 +334,8 @@ module ActionDispatch # :nodoc:
!@sending_file && @charset != false
end
- def remove_content_type!
- headers.delete CONTENT_TYPE
- end
-
def rack_response(status, header)
- if no_content_type
- remove_content_type!
- else
- assign_default_content_type_and_charset!(header)
- end
-
+ assign_default_content_type_and_charset!(header)
handle_conditional_get!
header[SET_COOKIE] = header[SET_COOKIE].join("\n") if header[SET_COOKIE].respond_to?(:join)
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index 4410c1b5d5..57f0963731 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -121,9 +121,9 @@ module ActionDispatch
def possibles(cache, options, depth = 0)
cache.fetch(:___routes) { [] } + options.find_all { |pair|
cache.key?(pair)
- }.map { |pair|
+ }.flat_map { |pair|
possibles(cache[pair], options, depth + 1)
- }.flatten(1)
+ }
end
# Returns +true+ if no missing keys are present, otherwise +false+.
diff --git a/actionpack/lib/action_dispatch/journey/gtg/builder.rb b/actionpack/lib/action_dispatch/journey/gtg/builder.rb
index 7d2791714b..450588cda6 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/builder.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/builder.rb
@@ -27,7 +27,7 @@ module ActionDispatch
marked[s] = true # mark s
s.group_by { |state| symbol(state) }.each do |sym, ps|
- u = ps.map { |l| followpos(l) }.flatten
+ u = ps.flat_map { |l| followpos(l) }
next if u.empty?
if u.uniq == [DUMMY]
@@ -90,7 +90,7 @@ module ActionDispatch
firstpos(node.left)
end
when Nodes::Or
- node.children.map { |c| firstpos(c) }.flatten.uniq
+ node.children.flat_map { |c| firstpos(c) }.uniq
when Nodes::Unary
firstpos(node.left)
when Nodes::Terminal
@@ -105,7 +105,7 @@ module ActionDispatch
when Nodes::Star
firstpos(node.left)
when Nodes::Or
- node.children.map { |c| lastpos(c) }.flatten.uniq
+ node.children.flat_map { |c| lastpos(c) }.uniq
when Nodes::Cat
if nullable?(node.right)
lastpos(node.left) | lastpos(node.right)
diff --git a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb
index 58ad803841..254c2befc4 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/simulator.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/simulator.rb
@@ -31,7 +31,7 @@ module ActionDispatch
return if acceptance_states.empty?
- memos = acceptance_states.map { |x| tt.memo(x) }.flatten.compact
+ memos = acceptance_states.flat_map { |x| tt.memo(x) }.compact
MatchData.new(memos)
end
diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
index 5a79059ed6..e6212b1ee2 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
@@ -114,17 +114,17 @@ module ActionDispatch
end
def states
- ss = @string_states.keys + @string_states.values.map(&:values).flatten
- rs = @regexp_states.keys + @regexp_states.values.map(&:values).flatten
+ ss = @string_states.keys + @string_states.values.flat_map(&:values)
+ rs = @regexp_states.keys + @regexp_states.values.flat_map(&:values)
(ss + rs).uniq
end
def transitions
- @string_states.map { |from, hash|
+ @string_states.flat_map { |from, hash|
hash.map { |s, to| [from, s, to] }
- }.flatten(1) + @regexp_states.map { |from, hash|
+ } + @regexp_states.flat_map { |from, hash|
hash.map { |s, to| [from, s, to] }
- }.flatten(1)
+ }
end
private
@@ -143,11 +143,11 @@ module ActionDispatch
def move_regexp(t, a)
return [] if t.empty?
- t.map { |s|
+ t.flat_map { |s|
if states = @regexp_states[s]
states.map { |re, v| re === a ? v : nil }
end
- }.flatten.compact.uniq
+ }.compact.uniq
end
def move_string(t, a)
diff --git a/actionpack/lib/action_dispatch/journey/nfa/dot.rb b/actionpack/lib/action_dispatch/journey/nfa/dot.rb
index 5c33a872e5..47bf76bdbf 100644
--- a/actionpack/lib/action_dispatch/journey/nfa/dot.rb
+++ b/actionpack/lib/action_dispatch/journey/nfa/dot.rb
@@ -16,9 +16,9 @@ module ActionDispatch
# end
# " #{n.object_id} [label=\"#{label}\", shape=box];"
#}
- #memo_edges = memos.map { |k, memos|
+ #memo_edges = memos.flat_map { |k, memos|
# (memos || []).map { |v| " #{k} -> #{v.object_id};" }
- #}.flatten.uniq
+ #}.uniq
<<-eodot
digraph nfa {
diff --git a/actionpack/lib/action_dispatch/journey/nfa/simulator.rb b/actionpack/lib/action_dispatch/journey/nfa/simulator.rb
index 5b40da6569..b23270db3c 100644
--- a/actionpack/lib/action_dispatch/journey/nfa/simulator.rb
+++ b/actionpack/lib/action_dispatch/journey/nfa/simulator.rb
@@ -34,7 +34,7 @@ module ActionDispatch
return if acceptance_states.empty?
- memos = acceptance_states.map { |x| tt.memo(x) }.flatten.compact
+ memos = acceptance_states.flat_map { |x| tt.memo(x) }.compact
MatchData.new(memos)
end
diff --git a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
index a3017aeea1..66e414213a 100644
--- a/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/nfa/transition_table.rb
@@ -42,7 +42,7 @@ module ActionDispatch
end
def states
- (@table.keys + @table.values.map(&:keys).flatten).uniq
+ (@table.keys + @table.values.flat_map(&:keys)).uniq
end
# Returns a generalized transition graph with reduced states. The states
@@ -93,7 +93,7 @@ module ActionDispatch
# Returns set of NFA states to which there is a transition on ast symbol
# +a+ from some state +s+ in +t+.
def following_states(t, a)
- Array(t).map { |s| inverted[s][a] }.flatten.uniq
+ Array(t).flat_map { |s| inverted[s][a] }.uniq
end
# Returns set of NFA states to which there is a transition on ast symbol
@@ -107,7 +107,7 @@ module ActionDispatch
end
def alphabet
- inverted.values.map(&:keys).flatten.compact.uniq.sort_by { |x| x.to_s }
+ inverted.values.flat_map(&:keys).compact.uniq.sort_by { |x| x.to_s }
end
# Returns a set of NFA states reachable from some NFA state +s+ in set
@@ -131,9 +131,9 @@ module ActionDispatch
end
def transitions
- @table.map { |to, hash|
+ @table.flat_map { |to, hash|
hash.map { |from, sym| [from, sym, to] }
- }.flatten(1)
+ }
end
private
diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb
index d37aa1fbe5..fb155e516f 100644
--- a/actionpack/lib/action_dispatch/journey/path/pattern.rb
+++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb
@@ -53,9 +53,9 @@ module ActionDispatch
end
def optional_names
- @optional_names ||= spec.grep(Nodes::Group).map { |group|
+ @optional_names ||= spec.grep(Nodes::Group).flat_map { |group|
group.grep(Nodes::Symbol)
- }.flatten.map { |n| n.name }.uniq
+ }.map { |n| n.name }.uniq
end
class RegexpOffsets < Journey::Visitors::Visitor # :nodoc:
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 18e64704f6..c0039fa3f5 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -74,7 +74,7 @@ module ActionDispatch
#
# domain: nil # Does not sets cookie domain. (default)
# domain: :all # Allow the cookie for the top most level
- # domain and subdomains.
+ # # domain and subdomains.
#
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
# * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
@@ -237,6 +237,15 @@ module ActionDispatch
@secure = secure
@options = options
@cookies = {}
+ @committed = false
+ end
+
+ def committed?; @committed; end
+
+ def commit!
+ @committed = true
+ @set_cookies.freeze
+ @delete_cookies.freeze
end
def each(&block)
@@ -336,8 +345,8 @@ module ActionDispatch
end
def recycle! #:nodoc:
- @set_cookies.clear
- @delete_cookies.clear
+ @set_cookies = {}
+ @delete_cookies = {}
end
mattr_accessor :always_write_cookie
@@ -551,9 +560,11 @@ module ActionDispatch
status, headers, body = @app.call(env)
if cookie_jar = env['action_dispatch.cookies']
- cookie_jar.write(headers)
- if headers[HTTP_HEADER].respond_to?(:join)
- headers[HTTP_HEADER] = headers[HTTP_HEADER].join("\n")
+ unless cookie_jar.committed?
+ cookie_jar.write(headers)
+ if headers[HTTP_HEADER].respond_to?(:join)
+ headers[HTTP_HEADER] = headers[HTTP_HEADER].join("\n")
+ end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 0b762aa9a4..357829e59f 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -708,7 +708,8 @@ module ActionDispatch
options[:constraints] ||= {}
unless shallow?
- options[:shallow_path] = options[:path] if args.any?
+ options[:shallow_path] ||= options[:path] if options.key?(:path)
+ options[:shallow_prefix] ||= options[:as] if options.key?(:as)
end
if options[:constraints].is_a?(Hash)
@@ -792,9 +793,16 @@ module ActionDispatch
# end
def namespace(path, options = {})
path = path.to_s
- options = { :path => path, :as => path, :module => path,
- :shallow_path => path, :shallow_prefix => path }.merge!(options)
- scope(options) { yield }
+
+ defaults = {
+ module: path,
+ path: options.fetch(:path, path),
+ as: options.fetch(:as, path),
+ shallow_path: options.fetch(:path, path),
+ shallow_prefix: options.fetch(:as, path)
+ }
+
+ scope(defaults.merge!(options)) { yield }
end
# === Parameter Restriction
@@ -1323,8 +1331,10 @@ module ActionDispatch
end
with_scope_level(:member) do
- scope(parent_resource.member_scope) do
- yield
+ if shallow?
+ shallow_scope(parent_resource.member_scope) { yield }
+ else
+ scope(parent_resource.member_scope) { yield }
end
end
end
@@ -1347,16 +1357,8 @@ module ActionDispatch
end
with_scope_level(:nested) do
- if shallow?
- with_exclusive_scope do
- if @scope[:shallow_path].blank?
- scope(parent_resource.nested_scope, nested_options) { yield }
- else
- scope(@scope[:shallow_path], :as => @scope[:shallow_prefix]) do
- scope(parent_resource.nested_scope, nested_options) { yield }
- end
- end
- end
+ if shallow? && nesting_depth > 1
+ shallow_scope(parent_resource.nested_scope, nested_options) { yield }
else
scope(parent_resource.nested_scope, nested_options) { yield }
end
@@ -1558,21 +1560,23 @@ module ActionDispatch
end
end
- def with_scope_level(kind, resource = parent_resource)
+ def with_scope_level(kind)
old, @scope[:scope_level] = @scope[:scope_level], kind
- old_resource, @scope[:scope_level_resource] = @scope[:scope_level_resource], resource
yield
ensure
@scope[:scope_level] = old
- @scope[:scope_level_resource] = old_resource
end
def resource_scope(kind, resource) #:nodoc:
- with_scope_level(kind, resource) do
- scope(parent_resource.resource_scope) do
- yield
- end
+ old_resource, @scope[:scope_level_resource] = @scope[:scope_level_resource], resource
+ @nesting.push(resource)
+
+ with_scope_level(kind) do
+ scope(parent_resource.resource_scope) { yield }
end
+ ensure
+ @nesting.pop
+ @scope[:scope_level_resource] = old_resource
end
def nested_options #:nodoc:
@@ -1584,6 +1588,10 @@ module ActionDispatch
options
end
+ def nesting_depth #:nodoc:
+ @nesting.size
+ end
+
def param_constraint? #:nodoc:
@scope[:constraints] && @scope[:constraints][parent_resource.param].is_a?(Regexp)
end
@@ -1596,18 +1604,20 @@ module ActionDispatch
flag && resource_method_scope? && CANONICAL_ACTIONS.include?(action.to_s)
end
- def shallow_scoping? #:nodoc:
- shallow? && @scope[:scope_level] == :member
+ def shallow_scope(path, options = {}) #:nodoc:
+ old_name_prefix, old_path = @scope[:as], @scope[:path]
+ @scope[:as], @scope[:path] = @scope[:shallow_prefix], @scope[:shallow_path]
+
+ scope(path, options) { yield }
+ ensure
+ @scope[:as], @scope[:path] = old_name_prefix, old_path
end
def path_for_action(action, path) #:nodoc:
- prefix = shallow_scoping? ?
- "#{@scope[:shallow_path]}/#{parent_resource.shallow_scope}" : @scope[:path]
-
if canonical_action?(action, path.blank?)
- prefix.to_s
+ @scope[:path].to_s
else
- "#{prefix}/#{action_path(action, path)}"
+ "#{@scope[:path]}/#{action_path(action, path)}"
end
end
@@ -1645,7 +1655,7 @@ module ActionDispatch
when :new
[prefix, :new, name_prefix, member_name]
when :member
- [prefix, shallow_scoping? ? @scope[:shallow_prefix] : name_prefix, member_name]
+ [prefix, name_prefix, member_name]
when :root
[name_prefix, collection_name, prefix]
else
@@ -1786,6 +1796,7 @@ module ActionDispatch
@set = set
@scope = { :path_names => @set.resources_path_names }
@concerns = {}
+ @nesting = []
end
include Base
diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb
new file mode 100644
index 0000000000..beaf35d3da
--- /dev/null
+++ b/actionpack/lib/action_pack/gem_version.rb
@@ -0,0 +1,15 @@
+module ActionPack
+ # Returns the version of the currently loaded ActionPack as a <tt>Gem::Version</tt>
+ def self.gem_version
+ Gem::Version.new VERSION::STRING
+ end
+
+ module VERSION
+ MAJOR = 4
+ MINOR = 2
+ TINY = 0
+ PRE = "alpha"
+
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
+ end
+end
diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb
index 75fb0d9532..7088cd2760 100644
--- a/actionpack/lib/action_pack/version.rb
+++ b/actionpack/lib/action_pack/version.rb
@@ -1,11 +1,8 @@
+require_relative 'gem_version'
+
module ActionPack
- # Returns the version of the currently loaded ActionPack as a Gem::Version
+ # Returns the version of the currently loaded ActionPack as a <tt>Gem::Version</tt>
def self.version
- Gem::Version.new "4.2.0.alpha"
- end
-
- module VERSION #:nodoc:
- MAJOR, MINOR, TINY, PRE = ActionPack.version.segments
- STRING = ActionPack.version.to_s
+ gem_version
end
end