actionpack 6.0.0.beta1 → 6.0.1.rc1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +125 -13
  3. data/README.rdoc +2 -1
  4. data/lib/abstract_controller/caching/fragments.rb +0 -1
  5. data/lib/abstract_controller/translation.rb +1 -0
  6. data/lib/action_controller.rb +4 -1
  7. data/lib/action_controller/metal.rb +3 -3
  8. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  9. data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
  10. data/lib/action_controller/metal/exceptions.rb +2 -2
  11. data/lib/action_controller/metal/force_ssl.rb +1 -2
  12. data/lib/action_controller/metal/helpers.rb +2 -2
  13. data/lib/action_controller/metal/implicit_render.rb +2 -2
  14. data/lib/action_controller/metal/live.rb +2 -2
  15. data/lib/action_controller/metal/mime_responds.rb +1 -1
  16. data/lib/action_controller/metal/params_wrapper.rb +2 -2
  17. data/lib/action_controller/metal/redirecting.rb +6 -27
  18. data/lib/action_controller/metal/renderers.rb +4 -4
  19. data/lib/action_controller/metal/rendering.rb +1 -1
  20. data/lib/action_controller/metal/request_forgery_protection.rb +2 -2
  21. data/lib/action_controller/metal/strong_parameters.rb +6 -12
  22. data/lib/action_controller/renderer.rb +2 -2
  23. data/lib/action_controller/template_assertions.rb +1 -1
  24. data/lib/action_controller/test_case.rb +3 -2
  25. data/lib/action_dispatch.rb +1 -1
  26. data/lib/action_dispatch/http/content_security_policy.rb +20 -9
  27. data/lib/action_dispatch/http/mime_negotiation.rb +5 -0
  28. data/lib/action_dispatch/http/mime_type.rb +13 -1
  29. data/lib/action_dispatch/http/response.rb +27 -7
  30. data/lib/action_dispatch/http/upload.rb +4 -1
  31. data/lib/action_dispatch/journey/formatter.rb +1 -1
  32. data/lib/action_dispatch/journey/path/pattern.rb +6 -1
  33. data/lib/action_dispatch/journey/route.rb +5 -4
  34. data/lib/action_dispatch/journey/routes.rb +0 -1
  35. data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
  36. data/lib/action_dispatch/middleware/cookies.rb +9 -10
  37. data/lib/action_dispatch/middleware/debug_exceptions.rb +8 -2
  38. data/lib/action_dispatch/middleware/debug_view.rb +19 -1
  39. data/lib/action_dispatch/middleware/exception_wrapper.rb +15 -10
  40. data/lib/action_dispatch/middleware/host_authorization.rb +2 -2
  41. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
  42. data/lib/action_dispatch/middleware/remote_ip.rb +3 -3
  43. data/lib/action_dispatch/middleware/session/cookie_store.rb +4 -3
  44. data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
  45. data/lib/action_dispatch/middleware/stack.rb +34 -2
  46. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  47. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  48. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  49. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  50. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +2 -2
  51. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +2 -2
  52. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +6 -2
  53. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  54. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -1
  55. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -1
  56. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
  57. data/lib/action_dispatch/railtie.rb +6 -2
  58. data/lib/action_dispatch/routing.rb +18 -18
  59. data/lib/action_dispatch/routing/mapper.rb +26 -11
  60. data/lib/action_dispatch/routing/route_set.rb +13 -15
  61. data/lib/action_dispatch/system_test_case.rb +43 -5
  62. data/lib/action_dispatch/system_testing/browser.rb +38 -7
  63. data/lib/action_dispatch/system_testing/driver.rb +10 -1
  64. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -2
  65. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -6
  66. data/lib/action_dispatch/testing/assertions.rb +1 -1
  67. data/lib/action_dispatch/testing/assertions/routing.rb +8 -1
  68. data/lib/action_dispatch/testing/integration.rb +2 -2
  69. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  70. data/lib/action_dispatch/testing/test_response.rb +1 -1
  71. data/lib/action_pack/gem_version.rb +2 -2
  72. metadata +20 -15
  73. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -157,24 +157,24 @@ module ActionController
157
157
  json = json.to_json(options) unless json.kind_of?(String)
158
158
 
159
159
  if options[:callback].present?
160
- if content_type.nil? || content_type == Mime[:json]
160
+ if media_type.nil? || media_type == Mime[:json]
161
161
  self.content_type = Mime[:js]
162
162
  end
163
163
 
164
164
  "/**/#{options[:callback]}(#{json})"
165
165
  else
166
- self.content_type ||= Mime[:json]
166
+ self.content_type = Mime[:json] if media_type.nil?
167
167
  json
168
168
  end
169
169
  end
170
170
 
171
171
  add :js do |js, options|
172
- self.content_type ||= Mime[:js]
172
+ self.content_type = Mime[:js] if media_type.nil?
173
173
  js.respond_to?(:to_js) ? js.to_js(options) : js
174
174
  end
175
175
 
176
176
  add :xml do |xml, options|
177
- self.content_type ||= Mime[:xml]
177
+ self.content_type = Mime[:xml] if media_type.nil?
178
178
  xml.respond_to?(:to_xml) ? xml.to_xml(options) : xml
179
179
  end
180
180
  end
@@ -73,7 +73,7 @@ module ActionController
73
73
  end
74
74
 
75
75
  def _set_rendered_content_type(format)
76
- if format && !response.content_type
76
+ if format && !response.media_type
77
77
  self.content_type = format.to_s
78
78
  end
79
79
  end
@@ -282,7 +282,7 @@ module ActionController #:nodoc:
282
282
 
283
283
  # Check for cross-origin JavaScript responses.
284
284
  def non_xhr_javascript_response? # :doc:
285
- content_type =~ %r(\A(?:text|application)/javascript) && !request.xhr?
285
+ %r(\A(?:text|application)/javascript).match?(media_type) && !request.xhr?
286
286
  end
287
287
 
288
288
  AUTHENTICITY_TOKEN_LENGTH = 32
@@ -431,7 +431,7 @@ module ActionController #:nodoc:
431
431
  The browser returned a 'null' origin for a request with origin-based forgery protection turned on. This usually
432
432
  means you have the 'no-referrer' Referrer-Policy header enabled, or that the request came from a site that
433
433
  refused to give its origin. This makes it impossible for Rails to verify the source of the requests. Likely the
434
- best solution is to change your referrer policy to something less strict like same-origin or strict-same-origin.
434
+ best solution is to change your referrer policy to something less strict like same-origin or strict-origin.
435
435
  If you cannot change the referrer policy, you can disable origin checking with the
436
436
  Rails.application.config.action_controller.forgery_protection_origin_check setting.
437
437
  MSG
@@ -4,7 +4,6 @@ require "active_support/core_ext/hash/indifferent_access"
4
4
  require "active_support/core_ext/array/wrap"
5
5
  require "active_support/core_ext/string/filters"
6
6
  require "active_support/core_ext/object/to_query"
7
- require "active_support/rescuable"
8
7
  require "action_dispatch/http/upload"
9
8
  require "rack/test"
10
9
  require "stringio"
@@ -674,18 +673,16 @@ module ActionController
674
673
  # Returns a new <tt>ActionController::Parameters</tt> instance with the
675
674
  # results of running +block+ once for every key. The values are unchanged.
676
675
  def transform_keys(&block)
677
- if block
678
- new_instance_with_inherited_permitted_status(
679
- @parameters.transform_keys(&block)
680
- )
681
- else
682
- @parameters.transform_keys
683
- end
676
+ return to_enum(:transform_keys) unless block_given?
677
+ new_instance_with_inherited_permitted_status(
678
+ @parameters.transform_keys(&block)
679
+ )
684
680
  end
685
681
 
686
682
  # Performs keys transformation and returns the altered
687
683
  # <tt>ActionController::Parameters</tt> instance.
688
684
  def transform_keys!(&block)
685
+ return to_enum(:transform_keys!) unless block_given?
689
686
  @parameters.transform_keys!(&block)
690
687
  self
691
688
  end
@@ -795,7 +792,7 @@ module ActionController
795
792
  @permitted = coder.map["ivars"][:@permitted]
796
793
  when "!ruby/object:ActionController::Parameters"
797
794
  # YAML's Object format. Only needed because of the format
798
- # backwardscompability above, otherwise equivalent to YAML's initialization.
795
+ # backwards compatibility above, otherwise equivalent to YAML's initialization.
799
796
  @parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
800
797
  end
801
798
  end
@@ -1092,9 +1089,6 @@ module ActionController
1092
1089
  # See ActionController::Parameters.require and ActionController::Parameters.permit
1093
1090
  # for more information.
1094
1091
  module StrongParameters
1095
- extend ActiveSupport::Concern
1096
- include ActiveSupport::Rescuable
1097
-
1098
1092
  # Returns a new ActionController::Parameters object that
1099
1093
  # has been instantiated with the <tt>request.parameters</tt>.
1100
1094
  def params
@@ -74,7 +74,7 @@ module ActionController
74
74
  # * <tt>:partial</tt> - See <tt>ActionView::PartialRenderer</tt> for details.
75
75
  # * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
76
76
  # It shouldn’t be used directly with unsanitized user input due to lack of validation.
77
- # * <tt>:inline</tt> - Renders a ERB template string.
77
+ # * <tt>:inline</tt> - Renders an ERB template string.
78
78
  # * <tt>:plain</tt> - Renders provided text and sets the content type as <tt>text/plain</tt>.
79
79
  # * <tt>:html</tt> - Renders the provided HTML safe string, otherwise
80
80
  # performs HTML escape on the string first. Sets the content type as <tt>text/html</tt>.
@@ -116,7 +116,7 @@ module ActionController
116
116
 
117
117
  RACK_VALUE_TRANSLATION = {
118
118
  https: ->(v) { v ? "on" : "off" },
119
- method: ->(v) { v.upcase },
119
+ method: ->(v) { -v.upcase },
120
120
  }
121
121
 
122
122
  def rack_key_for(key)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
- module TemplateAssertions
4
+ module TemplateAssertions # :nodoc:
5
5
  def assert_template(options = {}, message = nil)
6
6
  raise NoMethodError,
7
7
  "assert_template has been extracted to a gem. To continue using it,
@@ -457,6 +457,7 @@ module ActionController
457
457
  def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
458
458
  check_required_ivars
459
459
 
460
+ action = +action.to_s
460
461
  http_method = method.to_s.upcase
461
462
 
462
463
  @html_document = nil
@@ -488,11 +489,11 @@ module ActionController
488
489
  parameters[:format] = format
489
490
  end
490
491
 
491
- generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action.to_s))
492
+ generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
492
493
  generated_path = generated_path(generated_extras)
493
494
  query_string_keys = query_parameter_names(generated_extras)
494
495
 
495
- @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters, generated_path, query_string_keys)
496
+ @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
496
497
 
497
498
  @request.session.update(session) if session
498
499
  @request.flash.update(flash || {})
@@ -53,6 +53,7 @@ module ActionDispatch
53
53
  autoload :RequestId
54
54
  autoload :Callbacks
55
55
  autoload :Cookies
56
+ autoload :ActionableExceptions
56
57
  autoload :DebugExceptions
57
58
  autoload :DebugLocks
58
59
  autoload :DebugView
@@ -79,7 +80,6 @@ module ActionDispatch
79
80
  autoload :MimeNegotiation
80
81
  autoload :Parameters
81
82
  autoload :ParameterFilter
82
- autoload :Upload
83
83
  autoload :UploadedFile, "action_dispatch/http/upload"
84
84
  autoload :URL
85
85
  end
@@ -22,8 +22,9 @@ module ActionDispatch #:nodoc:
22
22
 
23
23
  if policy = request.content_security_policy
24
24
  nonce = request.content_security_policy_nonce
25
+ nonce_directives = request.content_security_policy_nonce_directives
25
26
  context = request.controller_instance || request
26
- headers[header_name(request)] = policy.build(context, nonce)
27
+ headers[header_name(request)] = policy.build(context, nonce, nonce_directives)
27
28
  end
28
29
 
29
30
  response
@@ -55,6 +56,7 @@ module ActionDispatch #:nodoc:
55
56
  POLICY_REPORT_ONLY = "action_dispatch.content_security_policy_report_only"
56
57
  NONCE_GENERATOR = "action_dispatch.content_security_policy_nonce_generator"
57
58
  NONCE = "action_dispatch.content_security_policy_nonce"
59
+ NONCE_DIRECTIVES = "action_dispatch.content_security_policy_nonce_directives"
58
60
 
59
61
  def content_security_policy
60
62
  get_header(POLICY)
@@ -80,6 +82,14 @@ module ActionDispatch #:nodoc:
80
82
  set_header(NONCE_GENERATOR, generator)
81
83
  end
82
84
 
85
+ def content_security_policy_nonce_directives
86
+ get_header(NONCE_DIRECTIVES)
87
+ end
88
+
89
+ def content_security_policy_nonce_directives=(generator)
90
+ set_header(NONCE_DIRECTIVES, generator)
91
+ end
92
+
83
93
  def content_security_policy_nonce
84
94
  if content_security_policy_nonce_generator
85
95
  if nonce = get_header(NONCE)
@@ -133,9 +143,9 @@ module ActionDispatch #:nodoc:
133
143
  worker_src: "worker-src"
134
144
  }.freeze
135
145
 
136
- NONCE_DIRECTIVES = %w[script-src style-src].freeze
146
+ DEFAULT_NONCE_DIRECTIVES = %w[script-src style-src].freeze
137
147
 
138
- private_constant :MAPPINGS, :DIRECTIVES, :NONCE_DIRECTIVES
148
+ private_constant :MAPPINGS, :DIRECTIVES, :DEFAULT_NONCE_DIRECTIVES
139
149
 
140
150
  attr_reader :directives
141
151
 
@@ -204,8 +214,9 @@ module ActionDispatch #:nodoc:
204
214
  end
205
215
  end
206
216
 
207
- def build(context = nil, nonce = nil)
208
- build_directives(context, nonce).compact.join("; ")
217
+ def build(context = nil, nonce = nil, nonce_directives = nil)
218
+ nonce_directives = DEFAULT_NONCE_DIRECTIVES if nonce_directives.nil?
219
+ build_directives(context, nonce, nonce_directives).compact.join("; ")
209
220
  end
210
221
 
211
222
  private
@@ -228,10 +239,10 @@ module ActionDispatch #:nodoc:
228
239
  end
229
240
  end
230
241
 
231
- def build_directives(context, nonce)
242
+ def build_directives(context, nonce, nonce_directives)
232
243
  @directives.map do |directive, sources|
233
244
  if sources.is_a?(Array)
234
- if nonce && nonce_directive?(directive)
245
+ if nonce && nonce_directive?(directive, nonce_directives)
235
246
  "#{directive} #{build_directive(sources, context).join(' ')} 'nonce-#{nonce}'"
236
247
  else
237
248
  "#{directive} #{build_directive(sources, context).join(' ')}"
@@ -266,8 +277,8 @@ module ActionDispatch #:nodoc:
266
277
  end
267
278
  end
268
279
 
269
- def nonce_directive?(directive)
270
- NONCE_DIRECTIVES.include?(directive)
280
+ def nonce_directive?(directive, nonce_directives)
281
+ nonce_directives.include?(directive)
271
282
  end
272
283
  end
273
284
  end
@@ -79,6 +79,11 @@ module ActionDispatch
79
79
  else
80
80
  [Mime[:html]]
81
81
  end
82
+
83
+ v = v.select do |format|
84
+ format.symbol || format.ref == "*/*"
85
+ end
86
+
82
87
  set_header k, v
83
88
  end
84
89
  end
@@ -170,6 +170,7 @@ module Mime
170
170
  def parse(accept_header)
171
171
  if !accept_header.include?(",")
172
172
  accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first
173
+ return [] unless accept_header
173
174
  parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact
174
175
  else
175
176
  list, index = [], 0
@@ -221,7 +222,18 @@ module Mime
221
222
 
222
223
  attr_reader :hash
223
224
 
225
+ MIME_NAME = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
226
+ MIME_PARAMETER_KEY = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
227
+ MIME_PARAMETER_VALUE = "#{Regexp.escape('"')}?[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}#{Regexp.escape('"')}?"
228
+ MIME_PARAMETER = "\s*\;\s+#{MIME_PARAMETER_KEY}(?:\=#{MIME_PARAMETER_VALUE})?"
229
+ MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?:\s*#{MIME_PARAMETER}\s*)*)\z/
230
+
231
+ class InvalidMimeType < StandardError; end
232
+
224
233
  def initialize(string, symbol = nil, synonyms = [])
234
+ unless MIME_REGEXP.match?(string)
235
+ raise InvalidMimeType, "#{string.inspect} is not a valid MIME type"
236
+ end
225
237
  @symbol, @synonyms = symbol, synonyms
226
238
  @string = string
227
239
  @hash = [@string, @synonyms, @symbol].hash
@@ -303,7 +315,7 @@ module Mime
303
315
  include Singleton
304
316
 
305
317
  def initialize
306
- super "*/*", :all
318
+ super "*/*", nil
307
319
  end
308
320
 
309
321
  def all?; true; end
@@ -85,6 +85,7 @@ module ActionDispatch # :nodoc:
85
85
 
86
86
  cattr_accessor :default_charset, default: "utf-8"
87
87
  cattr_accessor :default_headers
88
+ cattr_accessor :return_only_media_type_on_content_type, default: false
88
89
 
89
90
  include Rack::Response::Helpers
90
91
  # Aliasing these off because AD::Http::Cache::Response defines them.
@@ -242,8 +243,22 @@ module ActionDispatch # :nodoc:
242
243
  end
243
244
 
244
245
  # Content type of response.
245
- # It returns just MIME type and does NOT contain charset part.
246
246
  def content_type
247
+ if self.class.return_only_media_type_on_content_type
248
+ ActiveSupport::Deprecation.warn(
249
+ "Rails 6.1 will return Content-Type header without modification." \
250
+ " If you want just the MIME type, please use `#media_type` instead."
251
+ )
252
+
253
+ content_type = super
254
+ content_type ? content_type.split(/;\s*charset=/)[0].presence : content_type
255
+ else
256
+ super.presence
257
+ end
258
+ end
259
+
260
+ # Media type of response.
261
+ def media_type
247
262
  parsed_content_type_header.mime_type
248
263
  end
249
264
 
@@ -404,15 +419,18 @@ module ActionDispatch # :nodoc:
404
419
  end
405
420
 
406
421
  private
407
-
408
422
  ContentTypeHeader = Struct.new :mime_type, :charset
409
423
  NullContentTypeHeader = ContentTypeHeader.new nil, nil
410
424
 
425
+ CONTENT_TYPE_PARSER = /
426
+ \A
427
+ (?<mime_type>[^;\s]+\s*(?:;\s*(?:(?!charset)[^;\s])+)*)?
428
+ (?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?
429
+ /x # :nodoc:
430
+
411
431
  def parse_content_type(content_type)
412
- if content_type
413
- type, charset = content_type.split(/;\s*charset=/)
414
- type = nil if type && type.empty?
415
- ContentTypeHeader.new(type, charset)
432
+ if content_type && match = CONTENT_TYPE_PARSER.match(content_type)
433
+ ContentTypeHeader.new(match[:mime_type], match[:charset])
416
434
  else
417
435
  NullContentTypeHeader
418
436
  end
@@ -459,7 +477,7 @@ module ActionDispatch # :nodoc:
459
477
  end
460
478
 
461
479
  def assign_default_content_type_and_charset!
462
- return if content_type
480
+ return if media_type
463
481
 
464
482
  ct = parsed_content_type_header
465
483
  set_content_type(ct.mime_type || Mime[:html].to_s,
@@ -517,4 +535,6 @@ module ActionDispatch # :nodoc:
517
535
  end
518
536
  end
519
537
  end
538
+
539
+ ActiveSupport.run_load_hooks(:action_dispatch_response, Response)
520
540
  end
@@ -20,7 +20,6 @@ module ActionDispatch
20
20
  # A +Tempfile+ object with the actual uploaded file. Note that some of
21
21
  # its interface is available directly.
22
22
  attr_accessor :tempfile
23
- alias :to_io :tempfile
24
23
 
25
24
  # A string with the headers of the multipart request.
26
25
  attr_accessor :headers
@@ -84,6 +83,10 @@ module ActionDispatch
84
83
  def eof?
85
84
  @tempfile.eof?
86
85
  end
86
+
87
+ def to_io
88
+ @tempfile.to_io
89
+ end
87
90
  end
88
91
  end
89
92
  end
@@ -67,7 +67,7 @@ module ActionDispatch
67
67
  parameterized_parts = recall.merge(options)
68
68
 
69
69
  keys_to_keep = route.parts.reverse_each.drop_while { |part|
70
- !options.key?(part) || (options[part] || recall[part]).nil?
70
+ !(options.key?(part) || route.scope_options.key?(part)) || (options[part] || recall[part]).nil?
71
71
  } | route.required_parts
72
72
 
73
73
  parameterized_parts.delete_if do |bad_key, _|
@@ -119,7 +119,8 @@ module ActionDispatch
119
119
 
120
120
  class UnanchoredRegexp < AnchoredRegexp # :nodoc:
121
121
  def accept(node)
122
- %r{\A#{visit node}}
122
+ path = visit node
123
+ path == "/" ? %r{\A/} : %r{\A#{path}(?:\b|\Z|/)}
123
124
  end
124
125
  end
125
126
 
@@ -136,6 +137,10 @@ module ActionDispatch
136
137
  Array.new(length - 1) { |i| self[i + 1] }
137
138
  end
138
139
 
140
+ def named_captures
141
+ @names.zip(captures).to_h
142
+ end
143
+
139
144
  def [](x)
140
145
  idx = @offsets[x - 1] + x
141
146
  @match[idx]
@@ -4,9 +4,9 @@ module ActionDispatch
4
4
  # :stopdoc:
5
5
  module Journey
6
6
  class Route
7
- attr_reader :app, :path, :defaults, :name, :precedence
7
+ attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
8
+ :internal, :scope_options
8
9
 
9
- attr_reader :constraints, :internal
10
10
  alias :conditions :constraints
11
11
 
12
12
  module VerbMatchers
@@ -51,13 +51,13 @@ module ActionDispatch
51
51
 
52
52
  def self.build(name, app, path, constraints, required_defaults, defaults)
53
53
  request_method_match = verb_matcher(constraints.delete(:request_method))
54
- new name, app, path, constraints, required_defaults, defaults, request_method_match, 0
54
+ new name, app, path, constraints, required_defaults, defaults, request_method_match, 0, {}
55
55
  end
56
56
 
57
57
  ##
58
58
  # +path+ is a path constraint.
59
59
  # +constraints+ is a hash of constraints to be applied to this route.
60
- def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
60
+ def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, scope_options, internal = false)
61
61
  @name = name
62
62
  @app = app
63
63
  @path = path
@@ -72,6 +72,7 @@ module ActionDispatch
72
72
  @decorated_ast = nil
73
73
  @precedence = precedence
74
74
  @path_formatter = @path.build_formatter
75
+ @scope_options = scope_options
75
76
  @internal = internal
76
77
  end
77
78