aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md20
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb12
-rw-r--r--actionpack/lib/action_controller/metal.rb6
-rw-r--r--actionpack/lib/action_controller/metal/exceptions.rb2
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb4
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb2
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb4
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb11
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb11
-rw-r--r--actionpack/lib/action_dispatch/journey/formatter.rb2
-rw-r--r--actionpack/lib/action_dispatch/journey/gtg/transition_table.rb4
-rw-r--r--actionpack/lib/action_dispatch/journey/scanner.rb10
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb56
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb21
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb15
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb36
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb2
-rw-r--r--actionpack/test/controller/helper_test.rb22
-rw-r--r--actionpack/test/controller/integration_test.rb8
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb42
-rw-r--r--actionpack/test/dispatch/routing/route_set_test.rb80
-rw-r--r--actionpack/test/dispatch/routing_test.rb2
-rw-r--r--actionpack/test/fixtures/helpers_typo/admin/users_helper.rb5
-rw-r--r--actionpack/test/journey/route/definition/scanner_test.rb25
-rw-r--r--actionpack/test/journey/router_test.rb10
30 files changed, 343 insertions, 79 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index de9722c392..158b22c0cc 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,23 @@
+* Deprecate the `only_path` option on `*_path` helpers.
+
+ In cases where this option is set to `true`, the option is redundant and can
+ be safely removed; otherwise, the corresponding `*_url` helper should be
+ used instead.
+
+ Fixes #17294.
+
+ *Dan Olson*, *Godfrey Chan*
+
+* Improve Journey compliance to RFC 3986.
+
+ The scanner in Journey failed to recognize routes that use literals
+ from the sub-delims section of RFC 3986. It's now able to parse those
+ authorized delimiters and route as expected.
+
+ Fixes #17212.
+
+ *Nicolas Cavigneaux*
+
* Deprecate implicit Array conversion for Response objects. It was added
(using `#to_ary`) so we could conveniently use implicit splatting:
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 69a160fdc8..5196e67e55 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
s.add_dependency 'rack', '~> 1.6.0.beta'
s.add_dependency 'rack-test', '~> 0.6.2'
s.add_dependency 'rails-html-sanitizer', '~> 1.0', '>= 1.0.1'
- s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.3'
+ s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.4'
s.add_dependency 'actionview', version
s.add_development_dependency 'activemodel', version
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 95c67d482b..df7382f02d 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -150,7 +150,17 @@ module AbstractController
rescue LoadError => e
raise AbstractController::Helpers::MissingHelperError.new(e, file_name)
end
- file_name.camelize.constantize
+
+ mod_name = file_name.camelize
+ begin
+ mod_name.constantize
+ rescue LoadError
+ # dependencies.rb gives a similar error message but its wording is
+ # not as clear because it mentions autoloading. To the user all it
+ # matters is that a helper module couldn't be loaded, autoloading
+ # is an internal mechanism that should not leak.
+ raise NameError, "Couldn't find #{mod_name}, expected it to be defined in helpers/#{file_name}.rb"
+ end
when Module
arg
else
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index bfbc15a901..6dd213b2f7 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -165,7 +165,7 @@ module ActionController
headers["Location"] = url
end
- # basic url_for that can be overridden for more robust functionality
+ # Basic url_for that can be overridden for more robust functionality
def url_for(string)
string
end
@@ -182,7 +182,7 @@ module ActionController
body = [body] unless body.nil? || body.respond_to?(:each)
super
end
-
+
# Tests if render or redirect has already happened.
def performed?
response_body || (response && response.committed?)
@@ -237,7 +237,7 @@ module ActionController
end
end
- def _status_code
+ def _status_code #:nodoc:
@_status
end
end
diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb
index 3844dbf2a6..18e003741d 100644
--- a/actionpack/lib/action_controller/metal/exceptions.rb
+++ b/actionpack/lib/action_controller/metal/exceptions.rb
@@ -25,7 +25,7 @@ module ActionController
end
end
- class ActionController::UrlGenerationError < RoutingError #:nodoc:
+ class ActionController::UrlGenerationError < ActionControllerError #:nodoc:
end
class MethodNotAllowed < ActionControllerError #:nodoc:
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index dc572f13d2..591f881a53 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -216,11 +216,11 @@ module ActionController #:nodoc:
#
# Be sure to check the documentation of +respond_with+ and
# <tt>ActionController::MimeResponds.respond_to</tt> for more examples.
- def respond_to(*mimes, &block)
+ def respond_to(*mimes)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
collector = Collector.new(mimes, request.variant)
- block.call(collector) if block_given?
+ yield collector if block_given?
if format = collector.negotiate_format(request)
_process_format(format)
diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index 6921834044..545d4a7e6e 100644
--- a/actionpack/lib/action_controller/metal/rack_delegation.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -6,7 +6,7 @@ module ActionController
extend ActiveSupport::Concern
delegate :headers, :status=, :location=, :content_type=,
- :status, :location, :content_type, :_status_code, :to => "@_response"
+ :status, :location, :content_type, :response_code, :to => "@_response"
def dispatch(action, request)
set_response!(request)
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index a4f376816f..fd20682f8f 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -1,5 +1,6 @@
require 'rack/session/abstract/id'
require 'action_controller/metal/exceptions'
+require 'active_support/security_utils'
module ActionController #:nodoc:
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
@@ -305,8 +306,7 @@ module ActionController #:nodoc:
end
def compare_with_real_token(token, session)
- # Borrow a constant-time comparison from Rack
- Rack::Utils.secure_compare(token, real_csrf_token(session))
+ ActiveSupport::SecurityUtils.secure_compare(token, real_csrf_token(session))
end
def real_csrf_token(session)
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 7038f0997f..a5ee1e2159 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/string/filters'
require 'active_support/deprecation'
require 'active_support/rescuable'
require 'action_dispatch/http/upload'
@@ -114,10 +115,12 @@ module ActionController
def self.const_missing(const_name)
super unless const_name == :NEVER_UNPERMITTED_PARAMS
- ActiveSupport::Deprecation.warn "`ActionController::Parameters::NEVER_UNPERMITTED_PARAMS`"\
- " has been deprecated. Use "\
- "`ActionController::Parameters.always_permitted_parameters` instead."
- self.always_permitted_parameters
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
+ Use `ActionController::Parameters.always_permitted_parameters` instead.
+ MSG
+
+ always_permitted_parameters
end
# Returns a new instance of <tt>ActionController::Parameters</tt>.
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 20ae48d458..a5cd26a3c1 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -27,7 +27,7 @@ module ActionDispatch
def symbolized_path_parameters
ActiveSupport::Deprecation.warn(
- "`symbolized_path_parameters` is deprecated. Please use `path_parameters`"
+ '`symbolized_path_parameters` is deprecated. Please use `path_parameters`.'
)
path_parameters
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index a8785ee6bf..2a7bb374a5 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -328,7 +328,7 @@ module ActionDispatch
# Extracted into ActionDispatch::Request::Utils.deep_munge, but kept here for backwards compatibility.
def deep_munge(hash)
ActiveSupport::Deprecation.warn(
- "This method has been extracted into ActionDispatch::Request::Utils.deep_munge. Please start using that instead."
+ 'This method has been extracted into `ActionDispatch::Request::Utils.deep_munge`. Please start using that instead.'
)
Utils.deep_munge(hash)
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index c5e18048da..33de2f8b5f 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/module/attribute_accessors'
+require 'active_support/core_ext/string/filters'
require 'active_support/deprecation'
require 'action_dispatch/http/filter_redirect'
require 'monitor'
@@ -288,7 +289,12 @@ module ActionDispatch # :nodoc:
# as arrays work, and "flattening" responses, cascading to the rack body!
# Not sensible behavior.
def to_ary
- ActiveSupport::Deprecation.warn 'ActionDispatch::Response#to_ary no longer performs implicit conversion to an Array. Please use response.to_a instead, or a splat like `status, headers, body = *response`'
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `ActionDispatch::Response#to_ary` no longer performs implicit conversion
+ to an array. Please use `response.to_a` instead, or a splat like `status,
+ headers, body = *response`.
+ MSG
+
to_a
end
@@ -309,9 +315,6 @@ module ActionDispatch # :nodoc:
cookies
end
- def _status_code
- @status
- end
private
def before_committed
diff --git a/actionpack/lib/action_dispatch/journey/formatter.rb b/actionpack/lib/action_dispatch/journey/formatter.rb
index 59b353b1b7..992c1a9efe 100644
--- a/actionpack/lib/action_dispatch/journey/formatter.rb
+++ b/actionpack/lib/action_dispatch/journey/formatter.rb
@@ -40,7 +40,7 @@ module ActionDispatch
end
message = "No route matches #{Hash[constraints.sort].inspect}"
- message << " missing required keys: #{missing_keys.sort.inspect}" if name
+ message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
raise ActionController::UrlGenerationError, message
end
diff --git a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
index 990d2127ee..1b914f0637 100644
--- a/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
+++ b/actionpack/lib/action_dispatch/journey/gtg/transition_table.rb
@@ -88,13 +88,13 @@ module ActionDispatch
erb = File.read File.join(viz_dir, 'index.html.erb')
states = "function tt() { return #{to_json}; }"
- fun_routes = paths.shuffle.first(3).map do |ast|
+ fun_routes = paths.sample(3).map do |ast|
ast.map { |n|
case n
when Nodes::Symbol
case n.left
when ':id' then rand(100).to_s
- when ':format' then %w{ xml json }.shuffle.first
+ when ':format' then %w{ xml json }.sample
else
'omg'
end
diff --git a/actionpack/lib/action_dispatch/journey/scanner.rb b/actionpack/lib/action_dispatch/journey/scanner.rb
index 633be11a2d..19e0bc03d6 100644
--- a/actionpack/lib/action_dispatch/journey/scanner.rb
+++ b/actionpack/lib/action_dispatch/journey/scanner.rb
@@ -39,18 +39,18 @@ module ActionDispatch
[:SLASH, text]
when text = @ss.scan(/\*\w+/)
[:STAR, text]
- when text = @ss.scan(/\(/)
+ when text = @ss.scan(/(?<!\\)\(/)
[:LPAREN, text]
- when text = @ss.scan(/\)/)
+ when text = @ss.scan(/(?<!\\)\)/)
[:RPAREN, text]
when text = @ss.scan(/\|/)
[:OR, text]
when text = @ss.scan(/\./)
[:DOT, text]
- when text = @ss.scan(/:\w+/)
+ when text = @ss.scan(/(?<!\\):\w+/)
[:SYMBOL, text]
- when text = @ss.scan(/[\w%\-~]+/)
- [:LITERAL, text]
+ when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\:|\\\(|\\\))+/)
+ [:LITERAL, text.tr('\\', '')]
# any char
when text = @ss.scan(/./)
[:LITERAL, text]
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 274f6f2f22..ff72592b94 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -35,10 +35,23 @@ module ActionDispatch
if env['action_dispatch.show_detailed_exceptions']
request = Request.new(env)
+ traces = traces_from_wrapper(wrapper)
+
+ trace_to_show = 'Application Trace'
+ if traces[trace_to_show].empty?
+ trace_to_show = 'Full Trace'
+ end
+
+ if source_to_show = traces[trace_to_show].first
+ source_to_show_id = source_to_show[:id]
+ end
+
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
request: request,
exception: wrapper.exception,
- traces: traces_from_wrapper(wrapper),
+ traces: traces,
+ show_source_idx: source_to_show_id,
+ trace_to_show: trace_to_show,
routes_inspector: routes_inspector(exception),
source_extract: wrapper.source_extract,
line_number: wrapper.line_number,
@@ -97,31 +110,28 @@ module ActionDispatch
# Augment the exception traces by providing ids for all unique stack frame
def traces_from_wrapper(wrapper)
application_trace = wrapper.application_trace
- framework_trace = wrapper.framework_trace
- full_trace = wrapper.full_trace
-
- if application_trace && framework_trace
- id_counter = 0
-
- application_trace = application_trace.map do |trace|
- prev = id_counter
- id_counter += 1
- { id: prev, trace: trace }
- end
-
- framework_trace = framework_trace.map do |trace|
- prev = id_counter
- id_counter += 1
- { id: prev, trace: trace }
+ framework_trace = wrapper.framework_trace
+ full_trace = wrapper.full_trace
+
+ appplication_trace_with_ids = []
+ framework_trace_with_ids = []
+ full_trace_with_ids = []
+
+ if full_trace
+ full_trace.each_with_index do |trace, idx|
+ id_trace = {
+ id: idx,
+ trace: trace
+ }
+ appplication_trace_with_ids << id_trace if application_trace.include? trace
+ framework_trace_with_ids << id_trace if framework_trace.include? trace
+ full_trace_with_ids << id_trace
end
-
- full_trace = application_trace + framework_trace
end
-
{
- "Application Trace" => application_trace,
- "Framework Trace" => framework_trace,
- "Full Trace" => full_trace
+ "Application Trace" => appplication_trace_with_ids,
+ "Framework Trace" => framework_trace_with_ids,
+ "Full Trace" => full_trace_with_ids
}
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index b98b553c38..a6285848b5 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -6,16 +6,17 @@ module ActionDispatch
cattr_accessor :rescue_responses
@@rescue_responses = Hash.new(:internal_server_error)
@@rescue_responses.merge!(
- 'ActionController::RoutingError' => :not_found,
- 'AbstractController::ActionNotFound' => :not_found,
- 'ActionController::MethodNotAllowed' => :method_not_allowed,
- 'ActionController::UnknownHttpMethod' => :method_not_allowed,
- 'ActionController::NotImplemented' => :not_implemented,
- 'ActionController::UnknownFormat' => :not_acceptable,
- 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
- 'ActionDispatch::ParamsParser::ParseError' => :bad_request,
- 'ActionController::BadRequest' => :bad_request,
- 'ActionController::ParameterMissing' => :bad_request
+ 'ActionController::RoutingError' => :not_found,
+ 'AbstractController::ActionNotFound' => :not_found,
+ 'ActionController::MethodNotAllowed' => :method_not_allowed,
+ 'ActionController::UnknownHttpMethod' => :method_not_allowed,
+ 'ActionController::NotImplemented' => :not_implemented,
+ 'ActionController::UnknownFormat' => :not_acceptable,
+ 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
+ 'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity,
+ 'ActionDispatch::ParamsParser::ParseError' => :bad_request,
+ 'ActionController::BadRequest' => :bad_request,
+ 'ActionController::ParameterMissing' => :bad_request
)
cattr_accessor :rescue_templates
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
index ba29e26930..eabac3a9d2 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
@@ -1,7 +1,7 @@
<% if @source_extract %>
<% @source_extract.each_with_index do |extract_source, index| %>
<% if extract_source[:code] %>
- <div class="source <%="hidden" if index != 0%>" id="frame-source-<%=index%>">
+ <div class="source <%="hidden" if @show_source_idx != index%>" id="frame-source-<%=index%>">
<div class="info">
Extracted source (around line <strong>#<%= extract_source[:line_number] %></strong>):
</div>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
index f62caf51d7..ab57b11c7d 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
@@ -12,7 +12,7 @@
<% end %>
<% @traces.each do |name, trace| %>
- <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
+ <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == @trace_to_show) ? 'block' : 'none' %>;">
<pre><code><% trace.each do |frame| %><a class="trace-frames" data-frame-id="<%= frame[:id] %>" href="#"><%= frame[:trace] %></a><br><% end %></code></pre>
</div>
<% end %>
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index fc28740828..ac03ecb2c8 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -4,6 +4,7 @@ require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/module/remove_method'
+require 'active_support/core_ext/string/filters'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
require 'action_dispatch/routing/endpoint'
@@ -282,11 +283,19 @@ module ActionDispatch
def split_to(to)
case to
when Symbol
- ActiveSupport::Deprecation.warn "defining a route where `to` is a symbol is deprecated. Please change \"to: :#{to}\" to \"action: :#{to}\""
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Defining a route where `to` is a symbol is deprecated.
+ Please change `to: :#{to}` to `action: :#{to}`.
+ MSG
+
[nil, to.to_s]
when /#/ then to.split('#')
when String
- ActiveSupport::Deprecation.warn "defining a route where `to` is a controller without an action is deprecated. Please change \"to: :#{to}\" to \"controller: :#{to}\""
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Defining a route where `to` is a controller without an action is deprecated.
+ Please change `to: :#{to}` to `controller: :#{to}`.
+ MSG
+
[to, nil]
else
[]
@@ -434,7 +443,7 @@ module ActionDispatch
#
# Because requesting various HTTP verbs with a single action has security
# implications, you must either specify the actions in
- # the via options or use one of the HtttpHelpers[rdoc-ref:HttpHelpers]
+ # the via options or use one of the HttpHelpers[rdoc-ref:HttpHelpers]
# instead +match+
#
# === Options
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index f51bee3b31..a641ea3ea9 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -6,6 +6,7 @@ require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/string/filters'
require 'action_controller/metal/exceptions'
require 'action_dispatch/http/request'
require 'action_dispatch/routing/endpoint'
@@ -102,7 +103,10 @@ module ActionDispatch
end
def helpers
- ActiveSupport::Deprecation.warn("`named_routes.helpers` is deprecated, please use `route_defined?(route_name)` to see if a named route was defined.")
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `named_routes.helpers` is deprecated, please use `route_defined?(route_name)`
+ to see if a named route was defined.
+ MSG
@path_helpers + @url_helpers
end
@@ -134,8 +138,8 @@ module ActionDispatch
@url_helpers_module.send :undef_method, url_name
end
routes[key] = route
- define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
- define_url_helper @url_helpers_module, route, url_name, route.defaults, name, FULL
+ define_url_helper @path_helpers_module, route, path_name, route.defaults, name, LEGACY
+ define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
@path_helpers << path_name
@url_helpers << url_name
@@ -322,6 +326,32 @@ module ActionDispatch
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
FULL = ->(options) { ActionDispatch::Http::URL.full_url_for(options) }
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
+ LEGACY = ->(options) {
+ if options.key?(:only_path)
+ if options[:only_path]
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are calling a `*_path` helper with the `only_path` option
+ explicitly set to `true`. This option will stop working on
+ path helpers in Rails 5. Simply remove the `only_path: true`
+ argument from your call as it is redundant when applied to a
+ path helper.
+ MSG
+
+ PATH.call(options)
+ else
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are calling a `*_path` helper with the `only_path` option
+ explicitly set to `false`. This option will stop working on
+ path helpers in Rails 5. Use the corresponding `*_url` helper
+ instead.
+ MSG
+
+ FULL.call(options)
+ end
+ else
+ PATH.call(options)
+ end
+ }
# :startdoc:
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index 5c2905d1ac..da98b1d6ce 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -1,3 +1,3 @@
require 'active_support/deprecation'
-ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::TagAssertions has been extracted to the rails-dom-testing gem.")
+ActiveSupport::Deprecation.warn('`ActionDispatch::Assertions::TagAssertions` has been extracted to the rails-dom-testing gem.')
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index 20f99f19ee..936b8c2450 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -60,6 +60,12 @@ class HelpersPathsController < ActionController::Base
end
end
+class HelpersTypoController < ActionController::Base
+ path = File.expand_path('../../fixtures/helpers_typo', __FILE__)
+ $:.unshift(path)
+ self.helpers_path = path
+end
+
module LocalAbcHelper
def a() end
def b() end
@@ -82,6 +88,22 @@ class HelperPathsTest < ActiveSupport::TestCase
end
end
+class HelpersTypoControllerTest < ActiveSupport::TestCase
+ def setup
+ @autoload_paths = ActiveSupport::Dependencies.autoload_paths
+ ActiveSupport::Dependencies.autoload_paths = Array(HelpersTypoController.helpers_path)
+ end
+
+ def test_helper_typo_error_message
+ e = assert_raise(NameError) { HelpersTypoController.helper 'admin/users' }
+ assert_equal "Couldn't find Admin::UsersHelper, expected it to be defined in helpers/admin/users_helper.rb", e.message
+ end
+
+ def teardown
+ ActiveSupport::Dependencies.autoload_paths = @autoload_paths
+ end
+end
+
class HelperTest < ActiveSupport::TestCase
class TestController < ActionController::Base
attr_accessor :delegate_attr
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index c6380c7ffd..d91a1657b3 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -615,6 +615,8 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
get 'bar', :to => 'application_integration_test/test#index', :as => :bar
mount MountedApp => '/mounted', :as => "mounted"
+ get 'fooz' => proc { |env| [ 200, {'X-Cascade' => 'pass'}, [ "omg" ] ] }, :anchor => false
+ get 'fooz', :to => 'application_integration_test/test#index'
end
def app
@@ -631,6 +633,12 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
assert_equal '/mounted/baz', mounted.baz_path
end
+ test "path after cascade pass" do
+ get '/fooz'
+ assert_equal 'index', response.body
+ assert_equal '/fooz', path
+ end
+
test "route helpers after controller access" do
get '/'
assert_equal '/', empty_string_path
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 0add9fa3b0..f8851f0152 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -19,6 +19,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@closed = true
end
+ def method_that_raises
+ raise StandardError.new 'error in framework'
+ end
+
def call(env)
env['action_dispatch.show_detailed_exceptions'] = @detailed
req = ActionDispatch::Request.new(env)
@@ -57,7 +61,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
{})
raise ActionView::Template::Error.new(template, e)
end
-
+ when "/framework_raises"
+ method_that_raises
else
raise "puke!"
end
@@ -280,4 +285,39 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_select 'pre code', /\(eval\):1: syntax error, unexpected/
end
end
+
+ test 'debug exceptions app shows user code that caused the error in source view' do
+ @app = DevelopmentApp
+ Rails.stubs(:root).returns(Pathname.new('.'))
+ cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
+ bc.add_silencer { |line| line =~ /method_that_raises/ }
+ bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ end
+
+ get '/framework_raises', {}, {'action_dispatch.backtrace_cleaner' => cleaner}
+
+ # Assert correct error
+ assert_response 500
+ assert_select 'h2', /error in framework/
+
+ # assert source view line is the call to method_that_raises
+ assert_select 'div.source:not(.hidden)' do
+ assert_select 'pre .line.active', /method_that_raises/
+ end
+
+ # assert first source view (hidden) that throws the error
+ assert_select 'div.source:first' do
+ assert_select 'pre .line.active', /raise StandardError\.new/
+ end
+
+ # assert application trace refers to line that calls method_that_raises is first
+ assert_select '#Application-Trace' do
+ assert_select 'pre code a:first', %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call}
+ end
+
+ # assert framework trace that that threw the error is first
+ assert_select '#Framework-Trace' do
+ assert_select 'pre code a:first', /method_that_raises/
+ end
+ end
end
diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb
index c465d56bde..a7acc0de41 100644
--- a/actionpack/test/dispatch/routing/route_set_test.rb
+++ b/actionpack/test/dispatch/routing/route_set_test.rb
@@ -69,6 +69,86 @@ module ActionDispatch
end
end
+ test "only_path: true with *_url and no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal '/foo', url_helpers.foo_url(only_path: true)
+ end
+
+ test "only_path: false with *_url and no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_raises ArgumentError do
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false)
+ end
+ end
+
+ test "only_path: false with *_url and local :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false, host: 'example.com')
+ end
+
+ test "only_path: false with *_url and global :host option" do
+ @set.default_url_options = { host: 'example.com' }
+
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false)
+ end
+
+ test "only_path: true with *_path" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal '/foo', url_helpers.foo_path(only_path: true)
+ end
+ end
+
+ test "only_path: false with *_path with global :host option" do
+ @set.default_url_options = { host: 'example.com' }
+
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false)
+ end
+ end
+
+ test "only_path: false with *_path with local :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false, host: 'example.com')
+ end
+ end
+
+ test "only_path: false with *_path with no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_raises ArgumentError do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false)
+ end
+ end
+ end
+
test "explicit keys win over implicit keys" do
draw do
resources :foo do
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index d141210ad9..d0a624784a 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -4420,7 +4420,7 @@ class TestUrlGenerationErrors < ActionDispatch::IntegrationTest
include Routes.url_helpers
- test "url helpers raise a helpful error message whem generation fails" do
+ test "url helpers raise a helpful error message when generation fails" do
url, missing = { action: 'show', controller: 'products', id: nil }, [:id]
message = "No route matches #{url.inspect} missing required keys: #{missing.inspect}"
diff --git a/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb
new file mode 100644
index 0000000000..7d2326e04d
--- /dev/null
+++ b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb
@@ -0,0 +1,5 @@
+module Admin
+ module UsersHelpeR
+ end
+end
+
diff --git a/actionpack/test/journey/route/definition/scanner_test.rb b/actionpack/test/journey/route/definition/scanner_test.rb
index 624e6df51a..7a510f1e07 100644
--- a/actionpack/test/journey/route/definition/scanner_test.rb
+++ b/actionpack/test/journey/route/definition/scanner_test.rb
@@ -11,12 +11,25 @@ module ActionDispatch
# /page/:id(/:action)(.:format)
def test_tokens
[
- ['/', [[:SLASH, '/']]],
- ['*omg', [[:STAR, '*omg']]],
- ['/page', [[:SLASH, '/'], [:LITERAL, 'page']]],
- ['/~page', [[:SLASH, '/'], [:LITERAL, '~page']]],
- ['/pa-ge', [[:SLASH, '/'], [:LITERAL, 'pa-ge']]],
- ['/:page', [[:SLASH, '/'], [:SYMBOL, ':page']]],
+ ['/', [[:SLASH, '/']]],
+ ['*omg', [[:STAR, '*omg']]],
+ ['/page', [[:SLASH, '/'], [:LITERAL, 'page']]],
+ ['/page!', [[:SLASH, '/'], [:LITERAL, 'page!']]],
+ ['/page$', [[:SLASH, '/'], [:LITERAL, 'page$']]],
+ ['/page&', [[:SLASH, '/'], [:LITERAL, 'page&']]],
+ ["/page'", [[:SLASH, '/'], [:LITERAL, "page'"]]],
+ ['/page*', [[:SLASH, '/'], [:LITERAL, 'page*']]],
+ ['/page+', [[:SLASH, '/'], [:LITERAL, 'page+']]],
+ ['/page,', [[:SLASH, '/'], [:LITERAL, 'page,']]],
+ ['/page;', [[:SLASH, '/'], [:LITERAL, 'page;']]],
+ ['/page=', [[:SLASH, '/'], [:LITERAL, 'page=']]],
+ ['/page@', [[:SLASH, '/'], [:LITERAL, 'page@']]],
+ ['/page\:', [[:SLASH, '/'], [:LITERAL, 'page:']]],
+ ['/page\(', [[:SLASH, '/'], [:LITERAL, 'page(']]],
+ ['/page\)', [[:SLASH, '/'], [:LITERAL, 'page)']]],
+ ['/~page', [[:SLASH, '/'], [:LITERAL, '~page']]],
+ ['/pa-ge', [[:SLASH, '/'], [:LITERAL, 'pa-ge']]],
+ ['/:page', [[:SLASH, '/'], [:SYMBOL, ':page']]],
['/(:page)', [
[:SLASH, '/'],
[:LPAREN, '('],
diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb
index 8e90d4100f..fbac86e8ca 100644
--- a/actionpack/test/journey/router_test.rb
+++ b/actionpack/test/journey/router_test.rb
@@ -201,6 +201,16 @@ module ActionDispatch
assert_match(/missing required keys: \[:id\]/, error.message)
end
+ def test_does_not_include_missing_keys_message
+ route_name = "gorby_thunderhorse"
+
+ error = assert_raises(ActionController::UrlGenerationError) do
+ @formatter.generate(route_name, { }, { })
+ end
+
+ assert_no_match(/missing required keys: \[\]/, error.message)
+ end
+
def test_X_Cascade
add_routes @router, [ "/messages(.:format)" ]
resp = @router.serve(rails_env({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' }))