actionpack 5.1.7 → 5.2.4.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +282 -362
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/lib/abstract_controller.rb +3 -0
  6. data/lib/abstract_controller/asset_paths.rb +2 -0
  7. data/lib/abstract_controller/base.rb +10 -2
  8. data/lib/abstract_controller/caching.rb +3 -2
  9. data/lib/abstract_controller/caching/fragments.rb +30 -7
  10. data/lib/abstract_controller/callbacks.rb +25 -3
  11. data/lib/abstract_controller/collector.rb +2 -0
  12. data/lib/abstract_controller/error.rb +2 -0
  13. data/lib/abstract_controller/helpers.rb +4 -5
  14. data/lib/abstract_controller/logger.rb +2 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  16. data/lib/abstract_controller/rendering.rb +9 -16
  17. data/lib/abstract_controller/translation.rb +2 -0
  18. data/lib/abstract_controller/url_for.rb +2 -0
  19. data/lib/action_controller.rb +3 -0
  20. data/lib/action_controller/api.rb +2 -0
  21. data/lib/action_controller/api/api_rendering.rb +2 -0
  22. data/lib/action_controller/base.rb +3 -0
  23. data/lib/action_controller/caching.rb +2 -0
  24. data/lib/action_controller/form_builder.rb +2 -0
  25. data/lib/action_controller/log_subscriber.rb +5 -3
  26. data/lib/action_controller/metal.rb +13 -14
  27. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  28. data/lib/action_controller/metal/conditional_get.rb +4 -3
  29. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  30. data/lib/action_controller/metal/cookies.rb +2 -0
  31. data/lib/action_controller/metal/data_streaming.rb +7 -5
  32. data/lib/action_controller/metal/etag_with_flash.rb +2 -0
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +3 -2
  34. data/lib/action_controller/metal/exceptions.rb +2 -3
  35. data/lib/action_controller/metal/flash.rb +3 -2
  36. data/lib/action_controller/metal/force_ssl.rb +4 -2
  37. data/lib/action_controller/metal/head.rb +2 -0
  38. data/lib/action_controller/metal/helpers.rb +4 -3
  39. data/lib/action_controller/metal/http_authentication.rb +8 -9
  40. data/lib/action_controller/metal/implicit_render.rb +2 -0
  41. data/lib/action_controller/metal/instrumentation.rb +4 -6
  42. data/lib/action_controller/metal/live.rb +3 -1
  43. data/lib/action_controller/metal/mime_responds.rb +3 -1
  44. data/lib/action_controller/metal/parameter_encoding.rb +2 -0
  45. data/lib/action_controller/metal/params_wrapper.rb +14 -10
  46. data/lib/action_controller/metal/redirecting.rb +22 -11
  47. data/lib/action_controller/metal/renderers.rb +4 -3
  48. data/lib/action_controller/metal/rendering.rb +2 -2
  49. data/lib/action_controller/metal/request_forgery_protection.rb +62 -10
  50. data/lib/action_controller/metal/rescue.rb +5 -3
  51. data/lib/action_controller/metal/streaming.rb +3 -1
  52. data/lib/action_controller/metal/strong_parameters.rb +36 -25
  53. data/lib/action_controller/metal/testing.rb +2 -6
  54. data/lib/action_controller/metal/url_for.rb +2 -0
  55. data/lib/action_controller/railtie.rb +16 -4
  56. data/lib/action_controller/railties/helpers.rb +2 -0
  57. data/lib/action_controller/renderer.rb +2 -0
  58. data/lib/action_controller/template_assertions.rb +2 -0
  59. data/lib/action_controller/test_case.rb +16 -10
  60. data/lib/action_dispatch.rb +9 -5
  61. data/lib/action_dispatch/http/cache.rb +22 -14
  62. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  63. data/lib/action_dispatch/http/filter_parameters.rb +4 -2
  64. data/lib/action_dispatch/http/filter_redirect.rb +2 -0
  65. data/lib/action_dispatch/http/headers.rb +2 -0
  66. data/lib/action_dispatch/http/mime_negotiation.rb +4 -8
  67. data/lib/action_dispatch/http/mime_type.rb +15 -13
  68. data/lib/action_dispatch/http/mime_types.rb +17 -2
  69. data/lib/action_dispatch/http/parameter_filter.rb +2 -0
  70. data/lib/action_dispatch/http/parameters.rb +6 -9
  71. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  72. data/lib/action_dispatch/http/request.rb +36 -16
  73. data/lib/action_dispatch/http/response.rb +11 -9
  74. data/lib/action_dispatch/http/upload.rb +2 -0
  75. data/lib/action_dispatch/http/url.rb +5 -6
  76. data/lib/action_dispatch/journey.rb +2 -0
  77. data/lib/action_dispatch/journey/formatter.rb +4 -2
  78. data/lib/action_dispatch/journey/gtg/builder.rb +2 -0
  79. data/lib/action_dispatch/journey/gtg/simulator.rb +2 -8
  80. data/lib/action_dispatch/journey/gtg/transition_table.rb +3 -2
  81. data/lib/action_dispatch/journey/nfa/builder.rb +2 -0
  82. data/lib/action_dispatch/journey/nfa/dot.rb +12 -10
  83. data/lib/action_dispatch/journey/nfa/simulator.rb +2 -0
  84. data/lib/action_dispatch/journey/nfa/transition_table.rb +2 -0
  85. data/lib/action_dispatch/journey/nodes/node.rb +2 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +2 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  88. data/lib/action_dispatch/journey/route.rb +15 -6
  89. data/lib/action_dispatch/journey/router.rb +3 -1
  90. data/lib/action_dispatch/journey/router/utils.rb +14 -7
  91. data/lib/action_dispatch/journey/routes.rb +3 -1
  92. data/lib/action_dispatch/journey/scanner.rb +1 -0
  93. data/lib/action_dispatch/journey/visitors.rb +5 -3
  94. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  95. data/lib/action_dispatch/middleware/cookies.rb +148 -91
  96. data/lib/action_dispatch/middleware/debug_exceptions.rb +4 -2
  97. data/lib/action_dispatch/middleware/debug_locks.rb +9 -7
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +5 -6
  99. data/lib/action_dispatch/middleware/executor.rb +2 -0
  100. data/lib/action_dispatch/middleware/flash.rb +4 -2
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -4
  102. data/lib/action_dispatch/middleware/reloader.rb +2 -0
  103. data/lib/action_dispatch/middleware/remote_ip.rb +7 -5
  104. data/lib/action_dispatch/middleware/request_id.rb +3 -1
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +17 -1
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +13 -6
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +31 -32
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +2 -0
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -1
  110. data/lib/action_dispatch/middleware/ssl.rb +44 -38
  111. data/lib/action_dispatch/middleware/stack.rb +4 -2
  112. data/lib/action_dispatch/middleware/static.rb +14 -12
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
  116. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +6 -2
  117. data/lib/action_dispatch/railtie.rb +11 -1
  118. data/lib/action_dispatch/request/session.rb +16 -5
  119. data/lib/action_dispatch/request/utils.rb +6 -4
  120. data/lib/action_dispatch/routing.rb +3 -1
  121. data/lib/action_dispatch/routing/endpoint.rb +9 -2
  122. data/lib/action_dispatch/routing/inspector.rb +6 -4
  123. data/lib/action_dispatch/routing/mapper.rb +64 -52
  124. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  125. data/lib/action_dispatch/routing/redirection.rb +7 -5
  126. data/lib/action_dispatch/routing/route_set.rb +29 -24
  127. data/lib/action_dispatch/routing/routes_proxy.rb +5 -2
  128. data/lib/action_dispatch/routing/url_for.rb +25 -5
  129. data/lib/action_dispatch/system_test_case.rb +22 -6
  130. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  131. data/lib/action_dispatch/system_testing/driver.rb +9 -3
  132. data/lib/action_dispatch/system_testing/server.rb +2 -16
  133. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +12 -14
  134. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -2
  135. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  136. data/lib/action_dispatch/testing/assertion_response.rb +2 -0
  137. data/lib/action_dispatch/testing/assertions.rb +2 -0
  138. data/lib/action_dispatch/testing/assertions/response.rb +4 -2
  139. data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
  140. data/lib/action_dispatch/testing/integration.rb +24 -21
  141. data/lib/action_dispatch/testing/request_encoder.rb +3 -1
  142. data/lib/action_dispatch/testing/test_process.rb +2 -0
  143. data/lib/action_dispatch/testing/test_request.rb +3 -1
  144. data/lib/action_dispatch/testing/test_response.rb +23 -3
  145. data/lib/action_pack.rb +3 -1
  146. data/lib/action_pack/gem_version.rb +5 -3
  147. data/lib/action_pack/version.rb +2 -0
  148. metadata +23 -11
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/inflector/methods"
2
4
  require "active_support/dependencies"
3
5
 
@@ -95,8 +97,8 @@ module ActionDispatch
95
97
  middlewares.push(build_middleware(klass, args, block))
96
98
  end
97
99
 
98
- def build(app = Proc.new)
99
- middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }
100
+ def build(app = nil, &block)
101
+ middlewares.freeze.reverse.inject(app || block) { |a, e| e.build(a) }
100
102
  end
101
103
 
102
104
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rack/utils"
2
4
  require "active_support/core_ext/uri"
3
5
 
@@ -6,15 +8,15 @@ module ActionDispatch
6
8
  # When initialized, it can accept optional HTTP headers, which will be set
7
9
  # when a response containing a file's contents is delivered.
8
10
  #
9
- # This middleware will render the file specified in `env["PATH_INFO"]`
11
+ # This middleware will render the file specified in <tt>env["PATH_INFO"]</tt>
10
12
  # where the base path is in the +root+ directory. For example, if the +root+
11
- # is set to `public/`, then a request with `env["PATH_INFO"]` of
12
- # `assets/application.js` will return a response with the contents of a file
13
- # located at `public/assets/application.js` if the file exists. If the file
13
+ # is set to +public/+, then a request with <tt>env["PATH_INFO"]</tt> of
14
+ # +assets/application.js+ will return a response with the contents of a file
15
+ # located at +public/assets/application.js+ if the file exists. If the file
14
16
  # does not exist, a 404 "File not Found" response will be returned.
15
17
  class FileHandler
16
18
  def initialize(root, index: "index", headers: {})
17
- @root = root.chomp("/")
19
+ @root = root.chomp("/").b
18
20
  @file_server = ::Rack::File.new(@root, headers)
19
21
  @index = index
20
22
  end
@@ -23,8 +25,8 @@ module ActionDispatch
23
25
  # correct read permissions, the return value is a URI-escaped string
24
26
  # representing the filename. Otherwise, false is returned.
25
27
  #
26
- # Used by the `Static` class to check the existence of a valid file
27
- # in the server's `public/` directory (see Static#call).
28
+ # Used by the +Static+ class to check the existence of a valid file
29
+ # in the server's +public/+ directory (see Static#call).
28
30
  def match?(path)
29
31
  path = ::Rack::Utils.unescape_path path
30
32
  return false unless ::Rack::Utils.valid_path? path
@@ -33,7 +35,7 @@ module ActionDispatch
33
35
  paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"]
34
36
 
35
37
  if match = paths.detect { |p|
36
- path = File.join(@root, p.force_encoding(Encoding::UTF_8))
38
+ path = File.join(@root, p.b)
37
39
  begin
38
40
  File.file?(path) && File.readable?(path)
39
41
  rescue SystemCallError
@@ -41,7 +43,7 @@ module ActionDispatch
41
43
  end
42
44
 
43
45
  }
44
- return ::Rack::Utils.escape_path(match)
46
+ return ::Rack::Utils.escape_path(match).b
45
47
  end
46
48
  end
47
49
 
@@ -88,8 +90,8 @@ module ActionDispatch
88
90
  def gzip_file_path(path)
89
91
  can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
90
92
  gzip_path = "#{path}.gz"
91
- if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)))
92
- gzip_path
93
+ if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path).b))
94
+ gzip_path.b
93
95
  else
94
96
  false
95
97
  end
@@ -99,7 +101,7 @@ module ActionDispatch
99
101
  # This middleware will attempt to return the contents of a file's body from
100
102
  # disk in the response. If a file is not found on disk, the request will be
101
103
  # delegated to the application stack. This middleware is commonly initialized
102
- # to serve assets from a server's `public/` directory.
104
+ # to serve assets from a server's +public/+ directory.
103
105
  #
104
106
  # This middleware verifies the path to ensure that only files
105
107
  # living in the root directory can be rendered. A request cannot
@@ -0,0 +1,21 @@
1
+ <header>
2
+ <h1>
3
+ <%= @exception.class.to_s %>
4
+ <% if @request.parameters['controller'] %>
5
+ in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
6
+ <% end %>
7
+ </h1>
8
+ </header>
9
+
10
+ <div id="container">
11
+ <h2>
12
+ <%= h @exception.message %>
13
+ <% if %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}.match?(@exception.message) %>
14
+ <br />To resolve this issue run: bin/rails active_storage:install
15
+ <% end %>
16
+ </h2>
17
+
18
+ <%= render template: "rescues/_source" %>
19
+ <%= render template: "rescues/_trace" %>
20
+ <%= render template: "rescues/_request_and_response" %>
21
+ </div>
@@ -0,0 +1,13 @@
1
+ <%= @exception.class.to_s %><%
2
+ if @request.parameters['controller']
3
+ %> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
4
+ <% end %>
5
+
6
+ <%= @exception.message %>
7
+ <% if %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}.match?(@exception.message) %>
8
+ To resolve this issue run: bin/rails active_storage:install
9
+ <% end %>
10
+
11
+ <%= render template: "rescues/_source" %>
12
+ <%= render template: "rescues/_trace" %>
13
+ <%= render template: "rescues/_request_and_response" %>
@@ -106,6 +106,7 @@
106
106
 
107
107
  .line {
108
108
  padding-left: 10px;
109
+ white-space: pre;
109
110
  }
110
111
 
111
112
  .line:hover {
@@ -17,6 +17,10 @@
17
17
  line-height: 15px;
18
18
  }
19
19
 
20
+ #route_table thead tr.bottom th input#search {
21
+ -webkit-appearance: textfield;
22
+ }
23
+
20
24
  #route_table tbody tr {
21
25
  border-bottom: 1px solid #ddd;
22
26
  }
@@ -60,7 +64,7 @@
60
64
  <%= link_to "Path", "#", 'data-route-helper' => '_path',
61
65
  title: "Returns a relative path (without the http or domain)" %> /
62
66
  <%= link_to "Url", "#", 'data-route-helper' => '_url',
63
- title: "Returns an absolute url (with the http and domain)" %>
67
+ title: "Returns an absolute URL (with the http and domain)" %>
64
68
  </th>
65
69
  <th><%# HTTP Verb %>
66
70
  </th>
@@ -93,7 +97,7 @@
93
97
  }
94
98
  }
95
99
 
96
- // get JSON from url and invoke callback with result
100
+ // get JSON from URL and invoke callback with result
97
101
  function getJSON(url, success) {
98
102
  var xhr = new XMLHttpRequest();
99
103
  xhr.open('GET', url);
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "action_dispatch"
4
+ require "active_support/messages/rotation_configuration"
2
5
 
3
6
  module ActionDispatch
4
7
  class Railtie < Rails::Railtie # :nodoc:
@@ -16,14 +19,21 @@ module ActionDispatch
16
19
  config.action_dispatch.signed_cookie_salt = "signed cookie"
17
20
  config.action_dispatch.encrypted_cookie_salt = "encrypted cookie"
18
21
  config.action_dispatch.encrypted_signed_cookie_salt = "signed encrypted cookie"
22
+ config.action_dispatch.authenticated_encrypted_cookie_salt = "authenticated encrypted cookie"
23
+ config.action_dispatch.use_authenticated_cookie_encryption = false
19
24
  config.action_dispatch.perform_deep_munge = true
20
25
 
21
26
  config.action_dispatch.default_headers = {
22
27
  "X-Frame-Options" => "SAMEORIGIN",
23
28
  "X-XSS-Protection" => "1; mode=block",
24
- "X-Content-Type-Options" => "nosniff"
29
+ "X-Content-Type-Options" => "nosniff",
30
+ "X-Download-Options" => "noopen",
31
+ "X-Permitted-Cross-Domain-Policies" => "none",
32
+ "Referrer-Policy" => "strict-origin-when-cross-origin"
25
33
  }
26
34
 
35
+ config.action_dispatch.cookies_rotations = ActiveSupport::Messages::RotationConfiguration.new
36
+
27
37
  config.eager_load_namespaces << ActionDispatch
28
38
 
29
39
  initializer "action_dispatch.configure" do |app|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rack/session/abstract/id"
2
4
 
3
5
  module ActionDispatch
@@ -7,10 +9,10 @@ module ActionDispatch
7
9
  ENV_SESSION_KEY = Rack::RACK_SESSION # :nodoc:
8
10
  ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS # :nodoc:
9
11
 
10
- # Singleton object used to determine if an optional param wasn't specified
12
+ # Singleton object used to determine if an optional param wasn't specified.
11
13
  Unspecified = Object.new
12
14
 
13
- # Creates a session hash, merging the properties of the previous session if any
15
+ # Creates a session hash, merging the properties of the previous session if any.
14
16
  def self.create(store, req, default_options)
15
17
  session_was = find req
16
18
  session = Request::Session.new(store, req)
@@ -63,7 +65,7 @@ module ActionDispatch
63
65
  @req = req
64
66
  @delegate = {}
65
67
  @loaded = false
66
- @exists = nil # we haven't checked yet
68
+ @exists = nil # We haven't checked yet.
67
69
  end
68
70
 
69
71
  def id
@@ -79,7 +81,7 @@ module ActionDispatch
79
81
  options = self.options || {}
80
82
  @by.send(:delete_session, @req, options.id(@req), options)
81
83
 
82
- # Load the new sid to be written with the response
84
+ # Load the new sid to be written with the response.
83
85
  @loaded = false
84
86
  load_for_write!
85
87
  end
@@ -88,7 +90,13 @@ module ActionDispatch
88
90
  # +nil+ if the given key is not found in the session.
89
91
  def [](key)
90
92
  load_for_read!
91
- @delegate[key.to_s]
93
+ key = key.to_s
94
+
95
+ if key == "session_id"
96
+ id&.public_id
97
+ else
98
+ @delegate[key]
99
+ end
92
100
  end
93
101
 
94
102
  # Returns true if the session has the given key or false.
@@ -101,11 +109,13 @@ module ActionDispatch
101
109
 
102
110
  # Returns keys of the session as Array.
103
111
  def keys
112
+ load_for_read!
104
113
  @delegate.keys
105
114
  end
106
115
 
107
116
  # Returns values of the session as Array.
108
117
  def values
118
+ load_for_read!
109
119
  @delegate.values
110
120
  end
111
121
 
@@ -126,6 +136,7 @@ module ActionDispatch
126
136
  load_for_read!
127
137
  @delegate.dup.delete_if { |_, v| v.nil? }
128
138
  end
139
+ alias :to_h :to_hash
129
140
 
130
141
  # Updates the session with given Hash.
131
142
  #
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+
1
5
  module ActionDispatch
2
6
  class Request
3
7
  class Utils # :nodoc:
4
- mattr_accessor :perform_deep_munge
5
- self.perform_deep_munge = true
8
+ mattr_accessor :perform_deep_munge, default: true
6
9
 
7
10
  def self.each_param_value(params, &block)
8
11
  case params
@@ -40,7 +43,6 @@ module ActionDispatch
40
43
 
41
44
  class ParamEncoder # :nodoc:
42
45
  # Convert nested Hash to HashWithIndifferentAccess.
43
- #
44
46
  def self.normalize_encode_params(params)
45
47
  case params
46
48
  when Array
@@ -63,7 +65,7 @@ module ActionDispatch
63
65
  end
64
66
  end
65
67
 
66
- # Remove nils from the params hash
68
+ # Remove nils from the params hash.
67
69
  class NoNilParamEncoder < ParamEncoder # :nodoc:
68
70
  def self.handle_array(params)
69
71
  list = super
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/filters"
2
4
 
3
5
  module ActionDispatch
@@ -120,7 +122,7 @@ module ActionDispatch
120
122
  # controller :blog do
121
123
  # get 'blog/show' => :list
122
124
  # get 'blog/delete' => :delete
123
- # get 'blog/edit' => :edit
125
+ # get 'blog/edit' => :edit
124
126
  # end
125
127
  #
126
128
  # # provides named routes for show, delete, and edit
@@ -1,10 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionDispatch
2
4
  module Routing
3
5
  class Endpoint # :nodoc:
4
6
  def dispatcher?; false; end
5
7
  def redirect?; false; end
6
- def matches?(req); true; end
7
- def app; self; end
8
+ def matches?(req); true; end
9
+ def app; self; end
10
+ def rack_app; app; end
11
+
12
+ def engine?
13
+ rack_app.is_a?(Class) && rack_app < Rails::Engine
14
+ end
8
15
  end
9
16
  end
10
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "delegate"
2
4
  require "active_support/core_ext/string/strip"
3
5
 
@@ -13,7 +15,7 @@ module ActionDispatch
13
15
  end
14
16
 
15
17
  def rack_app
16
- app.app
18
+ app.rack_app
17
19
  end
18
20
 
19
21
  def path
@@ -45,7 +47,7 @@ module ActionDispatch
45
47
  end
46
48
 
47
49
  def engine?
48
- rack_app.respond_to?(:routes)
50
+ app.engine?
49
51
  end
50
52
  end
51
53
 
@@ -82,7 +84,7 @@ module ActionDispatch
82
84
 
83
85
  def normalize_filter(filter)
84
86
  if filter.is_a?(Hash) && filter[:controller]
85
- { controller: /#{filter[:controller].downcase.sub(/_?controller\z/, '').sub('::', '/')}/ }
87
+ { controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
86
88
  elsif filter
87
89
  { controller: /#{filter}/, action: /#{filter}/, verb: /#{filter}/, name: /#{filter}/, path: /#{filter}/ }
88
90
  end
@@ -196,7 +198,7 @@ module ActionDispatch
196
198
  @buffer << @view.render(partial: "routes/route", collection: routes)
197
199
  end
198
200
 
199
- # the header is part of the HTML page, so we don't construct it here.
201
+ # The header is part of the HTML page, so we don't construct it here.
200
202
  def header(routes)
201
203
  end
202
204
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash/slice"
2
4
  require "active_support/core_ext/enumerable"
3
5
  require "active_support/core_ext/array/extract_options"
@@ -17,9 +19,9 @@ module ActionDispatch
17
19
  CALL = ->(app, req) { app.call req.env }
18
20
 
19
21
  def initialize(app, constraints, strategy)
20
- # Unwrap Constraints objects. I don't actually think it's possible
22
+ # Unwrap Constraints objects. I don't actually think it's possible
21
23
  # to pass a Constraints object to this constructor, but there were
22
- # multiple places that kept testing children of this object. I
24
+ # multiple places that kept testing children of this object. I
23
25
  # *think* they were just being defensive, but I have no idea.
24
26
  if app.is_a?(self.class)
25
27
  constraints += app.constraints
@@ -219,7 +221,7 @@ module ActionDispatch
219
221
  private
220
222
  def add_wildcard_options(options, formatted, path_ast)
221
223
  # Add a constraint for wildcard route to make it non-greedy and match the
222
- # optional format part of the route by default
224
+ # optional format part of the route by default.
223
225
  if formatted != false
224
226
  path_ast.grep(Journey::Nodes::Star).each_with_object({}) { |node, hash|
225
227
  hash[node.name.to_sym] ||= /.+?/
@@ -306,7 +308,7 @@ module ActionDispatch
306
308
  def check_controller_and_action(path_params, controller, action)
307
309
  hash = check_part(:controller, controller, path_params, {}) do |part|
308
310
  translate_controller(part) {
309
- message = "'#{part}' is not a supported controller name. This can lead to potential routing problems."
311
+ message = "'#{part}' is not a supported controller name. This can lead to potential routing problems.".dup
310
312
  message << " See http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use"
311
313
 
312
314
  raise ArgumentError, message
@@ -388,7 +390,7 @@ module ActionDispatch
388
390
  # for root cases, where the latter is the correct one.
389
391
  def self.normalize_path(path)
390
392
  path = Journey::Router::Utils.normalize_path(path)
391
- path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^)]+\)$}
393
+ path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/(\(+[^)]+\)){1,}$}
392
394
  path
393
395
  end
394
396
 
@@ -397,7 +399,7 @@ module ActionDispatch
397
399
  end
398
400
 
399
401
  module Base
400
- # Matches a url pattern to one or more routes.
402
+ # Matches a URL pattern to one or more routes.
401
403
  #
402
404
  # You should not use the +match+ method in your router
403
405
  # without specifying an HTTP method.
@@ -407,7 +409,7 @@ module ActionDispatch
407
409
  # # sets :controller, :action and :id in params
408
410
  # match ':controller/:action/:id', via: [:get, :post]
409
411
  #
410
- # Note that +:controller+, +:action+ and +:id+ are interpreted as url
412
+ # Note that +:controller+, +:action+ and +:id+ are interpreted as URL
411
413
  # query parameters and thus available through +params+ in an action.
412
414
  #
413
415
  # If you want to expose your action to GET, use +get+ in the router:
@@ -456,7 +458,7 @@ module ActionDispatch
456
458
  #
457
459
  # === Options
458
460
  #
459
- # Any options not seen here are passed on as params with the url.
461
+ # Any options not seen here are passed on as params with the URL.
460
462
  #
461
463
  # [:controller]
462
464
  # The route's controller.
@@ -471,7 +473,17 @@ module ActionDispatch
471
473
  # <tt>params[<:param>]</tt>.
472
474
  # In your router:
473
475
  #
474
- # resources :user, param: :name
476
+ # resources :users, param: :name
477
+ #
478
+ # The +users+ resource here will have the following routes generated for it:
479
+ #
480
+ # GET /users(.:format)
481
+ # POST /users(.:format)
482
+ # GET /users/new(.:format)
483
+ # GET /users/:name/edit(.:format)
484
+ # GET /users/:name(.:format)
485
+ # PATCH/PUT /users/:name(.:format)
486
+ # DELETE /users/:name(.:format)
475
487
  #
476
488
  # You can override <tt>ActiveRecord::Base#to_param</tt> of a related
477
489
  # model to construct a URL:
@@ -482,8 +494,8 @@ module ActionDispatch
482
494
  # end
483
495
  # end
484
496
  #
485
- # user = User.find_by(name: 'Phusion')
486
- # user_path(user) # => "/users/Phusion"
497
+ # user = User.find_by(name: 'Phusion')
498
+ # user_path(user) # => "/users/Phusion"
487
499
  #
488
500
  # [:path]
489
501
  # The path prefix for the routes.
@@ -1252,7 +1264,7 @@ module ActionDispatch
1252
1264
  #
1253
1265
  # resource :profile
1254
1266
  #
1255
- # creates six different routes in your application, all mapping to
1267
+ # This creates six different routes in your application, all mapping to
1256
1268
  # the +Profiles+ controller (note that the controller is named after
1257
1269
  # the plural):
1258
1270
  #
@@ -1264,7 +1276,7 @@ module ActionDispatch
1264
1276
  # POST /profile
1265
1277
  #
1266
1278
  # === Options
1267
- # Takes same options as +resources+.
1279
+ # Takes same options as resources[rdoc-ref:#resources]
1268
1280
  def resource(*resources, &block)
1269
1281
  options = resources.extract_options!.dup
1270
1282
 
@@ -1329,7 +1341,7 @@ module ActionDispatch
1329
1341
  # DELETE /photos/:photo_id/comments/:id
1330
1342
  #
1331
1343
  # === Options
1332
- # Takes same options as <tt>Base#match</tt> as well as:
1344
+ # Takes same options as match[rdoc-ref:Base#match] as well as:
1333
1345
  #
1334
1346
  # [:path_names]
1335
1347
  # Allows you to change the segment component of the +edit+ and +new+ actions.
@@ -1337,14 +1349,14 @@ module ActionDispatch
1337
1349
  #
1338
1350
  # resources :posts, path_names: { new: "brand_new" }
1339
1351
  #
1340
- # The above example will now change /posts/new to /posts/brand_new
1352
+ # The above example will now change /posts/new to /posts/brand_new.
1341
1353
  #
1342
1354
  # [:path]
1343
1355
  # Allows you to change the path prefix for the resource.
1344
1356
  #
1345
1357
  # resources :posts, path: 'postings'
1346
1358
  #
1347
- # The resource and all segments will now route to /postings instead of /posts
1359
+ # The resource and all segments will now route to /postings instead of /posts.
1348
1360
  #
1349
1361
  # [:only]
1350
1362
  # Only generate routes for the given actions.
@@ -1539,7 +1551,7 @@ module ActionDispatch
1539
1551
  end
1540
1552
  end
1541
1553
 
1542
- # See ActionDispatch::Routing::Mapper::Scoping#namespace
1554
+ # See ActionDispatch::Routing::Mapper::Scoping#namespace.
1543
1555
  def namespace(path, options = {})
1544
1556
  if resource_scope?
1545
1557
  nested { super }
@@ -1559,10 +1571,10 @@ module ActionDispatch
1559
1571
  !parent_resource.singleton? && @scope[:shallow]
1560
1572
  end
1561
1573
 
1562
- # Matches a url pattern to one or more routes.
1574
+ # Matches a URL pattern to one or more routes.
1563
1575
  # For more information, see match[rdoc-ref:Base#match].
1564
1576
  #
1565
- # match 'path' => 'controller#action', via: patch
1577
+ # match 'path' => 'controller#action', via: :patch
1566
1578
  # match 'path', to: 'controller#action', via: :post
1567
1579
  # match 'path', 'otherpath', on: :member, via: :get
1568
1580
  def match(path, *rest, &block)
@@ -1850,7 +1862,7 @@ module ActionDispatch
1850
1862
  path_types.fetch(String, []).each do |_path|
1851
1863
  route_options = options.dup
1852
1864
  if _path && option_path
1853
- raise ArgumentError, "Ambigous route definition. Both :path and the route path where specified as strings."
1865
+ raise ArgumentError, "Ambiguous route definition. Both :path and the route path were specified as strings."
1854
1866
  end
1855
1867
  to = get_to_from_path(_path, to, route_options[:action])
1856
1868
  decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints)
@@ -2017,7 +2029,7 @@ module ActionDispatch
2017
2029
  # concerns :commentable
2018
2030
  # end
2019
2031
  #
2020
- # concerns also work in any routes helper that you want to use:
2032
+ # Concerns also work in any routes helper that you want to use:
2021
2033
  #
2022
2034
  # namespace :posts do
2023
2035
  # concerns :commentable
@@ -2035,7 +2047,7 @@ module ActionDispatch
2035
2047
  end
2036
2048
 
2037
2049
  module CustomUrls
2038
- # Define custom url helpers that will be added to the application's
2050
+ # Define custom URL helpers that will be added to the application's
2039
2051
  # routes. This allows you to override and/or replace the default behavior
2040
2052
  # of routing helpers, e.g:
2041
2053
  #
@@ -2051,37 +2063,37 @@ module ActionDispatch
2051
2063
  # { controller: "pages", action: "index", subdomain: "www" }
2052
2064
  # end
2053
2065
  #
2054
- # The return value from the block passed to `direct` must be a valid set of
2055
- # arguments for `url_for` which will actually build the url string. This can
2066
+ # The return value from the block passed to +direct+ must be a valid set of
2067
+ # arguments for +url_for+ which will actually build the URL string. This can
2056
2068
  # be one of the following:
2057
2069
  #
2058
- # * A string, which is treated as a generated url
2059
- # * A hash, e.g. { controller: "pages", action: "index" }
2060
- # * An array, which is passed to `polymorphic_url`
2061
- # * An Active Model instance
2062
- # * An Active Model class
2070
+ # * A string, which is treated as a generated URL
2071
+ # * A hash, e.g. <tt>{ controller: "pages", action: "index" }</tt>
2072
+ # * An array, which is passed to +polymorphic_url+
2073
+ # * An Active Model instance
2074
+ # * An Active Model class
2063
2075
  #
2064
- # NOTE: Other url helpers can be called in the block but be careful not to invoke
2065
- # your custom url helper again otherwise it will result in a stack overflow error
2076
+ # NOTE: Other URL helpers can be called in the block but be careful not to invoke
2077
+ # your custom URL helper again otherwise it will result in a stack overflow error.
2066
2078
  #
2067
2079
  # You can also specify default options that will be passed through to
2068
- # your url helper definition, e.g:
2080
+ # your URL helper definition, e.g:
2069
2081
  #
2070
2082
  # direct :browse, page: 1, size: 10 do |options|
2071
2083
  # [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
2072
2084
  # end
2073
2085
  #
2074
- # In this instance the `params` object comes from the context in which the the
2075
- # block is executed, e.g. generating a url inside a controller action or a view.
2076
- # If the block is executed where there isn't a params object such as this:
2086
+ # In this instance the +params+ object comes from the context in which the
2087
+ # block is executed, e.g. generating a URL inside a controller action or a view.
2088
+ # If the block is executed where there isn't a +params+ object such as this:
2077
2089
  #
2078
2090
  # Rails.application.routes.url_helpers.browse_path
2079
2091
  #
2080
- # then it will raise a `NameError`. Because of this you need to be aware of the
2081
- # context in which you will use your custom url helper when defining it.
2092
+ # then it will raise a +NameError+. Because of this you need to be aware of the
2093
+ # context in which you will use your custom URL helper when defining it.
2082
2094
  #
2083
- # NOTE: The `direct` method can't be used inside of a scope block such as
2084
- # `namespace` or `scope` and will raise an error if it detects that it is.
2095
+ # NOTE: The +direct+ method can't be used inside of a scope block such as
2096
+ # +namespace+ or +scope+ and will raise an error if it detects that it is.
2085
2097
  def direct(name, options = {}, &block)
2086
2098
  unless @scope.root?
2087
2099
  raise RuntimeError, "The direct method can't be used inside a routes scope block"
@@ -2090,9 +2102,9 @@ module ActionDispatch
2090
2102
  @set.add_url_helper(name, options, &block)
2091
2103
  end
2092
2104
 
2093
- # Define custom polymorphic mappings of models to urls. This alters the
2094
- # behavior of `polymorphic_url` and consequently the behavior of
2095
- # `link_to` and `form_for` when passed a model instance, e.g:
2105
+ # Define custom polymorphic mappings of models to URLs. This alters the
2106
+ # behavior of +polymorphic_url+ and consequently the behavior of
2107
+ # +link_to+ and +form_for+ when passed a model instance, e.g:
2096
2108
  #
2097
2109
  # resource :basket
2098
2110
  #
@@ -2100,10 +2112,10 @@ module ActionDispatch
2100
2112
  # [:basket]
2101
2113
  # end
2102
2114
  #
2103
- # This will now generate "/basket" when a `Basket` instance is passed to
2104
- # `link_to` or `form_for` instead of the standard "/baskets/:id".
2115
+ # This will now generate "/basket" when a +Basket+ instance is passed to
2116
+ # +link_to+ or +form_for+ instead of the standard "/baskets/:id".
2105
2117
  #
2106
- # NOTE: This custom behavior only applies to simple polymorphic urls where
2118
+ # NOTE: This custom behavior only applies to simple polymorphic URLs where
2107
2119
  # a single model instance is passed and not more complicated forms, e.g:
2108
2120
  #
2109
2121
  # # config/routes.rb
@@ -2118,8 +2130,8 @@ module ActionDispatch
2118
2130
  # link_to "Profile", @current_user
2119
2131
  # link_to "Profile", [:admin, @current_user]
2120
2132
  #
2121
- # The first `link_to` will generate "/profile" but the second will generate
2122
- # the standard polymorphic url of "/admin/users/1".
2133
+ # The first +link_to+ will generate "/profile" but the second will generate
2134
+ # the standard polymorphic URL of "/admin/users/1".
2123
2135
  #
2124
2136
  # You can pass options to a polymorphic mapping - the arity for the block
2125
2137
  # needs to be two as the instance is passed as the first argument, e.g:
@@ -2128,12 +2140,12 @@ module ActionDispatch
2128
2140
  # [:basket, options]
2129
2141
  # end
2130
2142
  #
2131
- # This generates the url "/basket#items" because when the last item in an
2132
- # array passed to `polymorphic_url` is a hash then it's treated as options
2133
- # to the url helper that gets called.
2143
+ # This generates the URL "/basket#items" because when the last item in an
2144
+ # array passed to +polymorphic_url+ is a hash then it's treated as options
2145
+ # to the URL helper that gets called.
2134
2146
  #
2135
- # NOTE: The `resolve` method can't be used inside of a scope block such as
2136
- # `namespace` or `scope` and will raise an error if it detects that it is.
2147
+ # NOTE: The +resolve+ method can't be used inside of a scope block such as
2148
+ # +namespace+ or +scope+ and will raise an error if it detects that it is.
2137
2149
  def resolve(*args, &block)
2138
2150
  unless @scope.root?
2139
2151
  raise RuntimeError, "The resolve method can't be used inside a routes scope block"