actionpack 4.0.13 → 4.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +131 -1636
  3. data/README.rdoc +1 -6
  4. data/lib/abstract_controller.rb +1 -2
  5. data/lib/abstract_controller/base.rb +3 -25
  6. data/lib/abstract_controller/callbacks.rb +4 -2
  7. data/lib/abstract_controller/collector.rb +11 -1
  8. data/lib/abstract_controller/helpers.rb +18 -15
  9. data/lib/abstract_controller/rendering.rb +48 -127
  10. data/lib/action_controller.rb +1 -17
  11. data/lib/action_controller/base.rb +14 -6
  12. data/lib/action_controller/caching.rb +1 -11
  13. data/lib/action_controller/log_subscriber.rb +1 -1
  14. data/lib/action_controller/metal.rb +0 -4
  15. data/lib/action_controller/metal/flash.rb +17 -0
  16. data/lib/action_controller/metal/force_ssl.rb +1 -1
  17. data/lib/action_controller/metal/head.rb +1 -3
  18. data/lib/action_controller/metal/helpers.rb +6 -2
  19. data/lib/action_controller/metal/http_authentication.rb +7 -14
  20. data/lib/action_controller/metal/instrumentation.rb +1 -1
  21. data/lib/action_controller/metal/live.rb +74 -0
  22. data/lib/action_controller/metal/mime_responds.rb +93 -16
  23. data/lib/action_controller/metal/params_wrapper.rb +4 -11
  24. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  25. data/lib/action_controller/metal/redirecting.rb +20 -20
  26. data/lib/action_controller/metal/renderers.rb +8 -5
  27. data/lib/action_controller/metal/rendering.rb +14 -11
  28. data/lib/action_controller/metal/request_forgery_protection.rb +67 -13
  29. data/lib/action_controller/metal/responder.rb +12 -2
  30. data/lib/action_controller/metal/streaming.rb +18 -20
  31. data/lib/action_controller/metal/strong_parameters.rb +22 -34
  32. data/lib/action_controller/railtie.rb +0 -1
  33. data/lib/action_controller/test_case.rb +0 -15
  34. data/lib/action_dispatch.rb +1 -0
  35. data/lib/action_dispatch/http/headers.rb +1 -3
  36. data/lib/action_dispatch/http/mime_negotiation.rb +16 -2
  37. data/lib/action_dispatch/http/mime_type.rb +4 -22
  38. data/lib/action_dispatch/http/mime_types.rb +1 -0
  39. data/lib/action_dispatch/http/parameters.rb +18 -19
  40. data/lib/action_dispatch/http/request.rb +16 -25
  41. data/lib/action_dispatch/http/response.rb +21 -8
  42. data/lib/action_dispatch/http/upload.rb +0 -13
  43. data/lib/action_dispatch/http/url.rb +10 -18
  44. data/lib/action_dispatch/journey/formatter.rb +3 -3
  45. data/lib/action_dispatch/journey/gtg/transition_table.rb +3 -5
  46. data/lib/action_dispatch/journey/parser.rb +1 -1
  47. data/lib/action_dispatch/journey/parser.y +1 -0
  48. data/lib/action_dispatch/journey/router.rb +7 -1
  49. data/lib/action_dispatch/journey/router/utils.rb +1 -1
  50. data/lib/action_dispatch/journey/visitors.rb +26 -47
  51. data/lib/action_dispatch/middleware/callbacks.rb +6 -6
  52. data/lib/action_dispatch/middleware/cookies.rb +15 -15
  53. data/lib/action_dispatch/middleware/debug_exceptions.rb +21 -13
  54. data/lib/action_dispatch/middleware/exception_wrapper.rb +1 -1
  55. data/lib/action_dispatch/middleware/flash.rb +5 -11
  56. data/lib/action_dispatch/middleware/params_parser.rb +1 -1
  57. data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
  58. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  59. data/lib/action_dispatch/middleware/session/cookie_store.rb +4 -3
  60. data/lib/action_dispatch/middleware/show_exceptions.rb +5 -2
  61. data/lib/action_dispatch/middleware/ssl.rb +1 -1
  62. data/lib/action_dispatch/middleware/static.rb +5 -25
  63. data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
  64. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  65. data/lib/action_dispatch/middleware/templates/rescues/{_trace.erb → _trace.html.erb} +0 -0
  66. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +15 -0
  67. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +1 -1
  68. data/lib/action_dispatch/middleware/templates/rescues/{missing_template.erb → missing_template.html.erb} +1 -1
  69. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  70. data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +1 -1
  71. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  72. data/lib/action_dispatch/middleware/templates/rescues/{template_error.erb → template_error.html.erb} +1 -1
  73. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +8 -0
  74. data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
  75. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  76. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -3
  77. data/lib/action_dispatch/railtie.rb +1 -2
  78. data/lib/action_dispatch/request/session.rb +12 -0
  79. data/lib/action_dispatch/request/utils.rb +24 -0
  80. data/lib/action_dispatch/routing.rb +7 -6
  81. data/lib/action_dispatch/routing/inspector.rb +4 -4
  82. data/lib/action_dispatch/routing/mapper.rb +81 -138
  83. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -0
  84. data/lib/action_dispatch/routing/redirection.rb +34 -27
  85. data/lib/action_dispatch/routing/route_set.rb +43 -37
  86. data/lib/action_dispatch/routing/url_for.rb +3 -1
  87. data/lib/action_dispatch/testing/assertions/response.rb +8 -15
  88. data/lib/action_dispatch/testing/assertions/selector.rb +4 -4
  89. data/lib/action_dispatch/testing/integration.rb +1 -7
  90. data/lib/action_pack/version.rb +1 -1
  91. metadata +43 -167
  92. data/lib/abstract_controller/layouts.rb +0 -423
  93. data/lib/abstract_controller/view_paths.rb +0 -96
  94. data/lib/action_controller/deprecated.rb +0 -7
  95. data/lib/action_controller/deprecated/integration_test.rb +0 -5
  96. data/lib/action_controller/record_identifier.rb +0 -31
  97. data/lib/action_controller/vendor/html-scanner.rb +0 -5
  98. data/lib/action_view.rb +0 -93
  99. data/lib/action_view/base.rb +0 -205
  100. data/lib/action_view/buffers.rb +0 -49
  101. data/lib/action_view/context.rb +0 -36
  102. data/lib/action_view/dependency_tracker.rb +0 -93
  103. data/lib/action_view/digestor.rb +0 -113
  104. data/lib/action_view/flows.rb +0 -76
  105. data/lib/action_view/helpers.rb +0 -58
  106. data/lib/action_view/helpers/active_model_helper.rb +0 -49
  107. data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
  108. data/lib/action_view/helpers/asset_url_helper.rb +0 -355
  109. data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
  110. data/lib/action_view/helpers/cache_helper.rb +0 -196
  111. data/lib/action_view/helpers/capture_helper.rb +0 -216
  112. data/lib/action_view/helpers/controller_helper.rb +0 -25
  113. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  114. data/lib/action_view/helpers/date_helper.rb +0 -1087
  115. data/lib/action_view/helpers/debug_helper.rb +0 -39
  116. data/lib/action_view/helpers/form_helper.rb +0 -1882
  117. data/lib/action_view/helpers/form_options_helper.rb +0 -838
  118. data/lib/action_view/helpers/form_tag_helper.rb +0 -785
  119. data/lib/action_view/helpers/javascript_helper.rb +0 -117
  120. data/lib/action_view/helpers/number_helper.rb +0 -451
  121. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  122. data/lib/action_view/helpers/record_tag_helper.rb +0 -106
  123. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  124. data/lib/action_view/helpers/sanitize_helper.rb +0 -256
  125. data/lib/action_view/helpers/tag_helper.rb +0 -173
  126. data/lib/action_view/helpers/tags.rb +0 -39
  127. data/lib/action_view/helpers/tags/base.rb +0 -148
  128. data/lib/action_view/helpers/tags/check_box.rb +0 -64
  129. data/lib/action_view/helpers/tags/checkable.rb +0 -16
  130. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -53
  131. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
  132. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
  133. data/lib/action_view/helpers/tags/collection_select.rb +0 -28
  134. data/lib/action_view/helpers/tags/color_field.rb +0 -25
  135. data/lib/action_view/helpers/tags/date_field.rb +0 -13
  136. data/lib/action_view/helpers/tags/date_select.rb +0 -72
  137. data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
  138. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
  139. data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
  140. data/lib/action_view/helpers/tags/email_field.rb +0 -8
  141. data/lib/action_view/helpers/tags/file_field.rb +0 -8
  142. data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
  143. data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
  144. data/lib/action_view/helpers/tags/label.rb +0 -65
  145. data/lib/action_view/helpers/tags/month_field.rb +0 -13
  146. data/lib/action_view/helpers/tags/number_field.rb +0 -18
  147. data/lib/action_view/helpers/tags/password_field.rb +0 -12
  148. data/lib/action_view/helpers/tags/radio_button.rb +0 -31
  149. data/lib/action_view/helpers/tags/range_field.rb +0 -8
  150. data/lib/action_view/helpers/tags/search_field.rb +0 -22
  151. data/lib/action_view/helpers/tags/select.rb +0 -40
  152. data/lib/action_view/helpers/tags/tel_field.rb +0 -8
  153. data/lib/action_view/helpers/tags/text_area.rb +0 -18
  154. data/lib/action_view/helpers/tags/text_field.rb +0 -30
  155. data/lib/action_view/helpers/tags/time_field.rb +0 -13
  156. data/lib/action_view/helpers/tags/time_select.rb +0 -8
  157. data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
  158. data/lib/action_view/helpers/tags/url_field.rb +0 -8
  159. data/lib/action_view/helpers/tags/week_field.rb +0 -13
  160. data/lib/action_view/helpers/text_helper.rb +0 -448
  161. data/lib/action_view/helpers/translation_helper.rb +0 -112
  162. data/lib/action_view/helpers/url_helper.rb +0 -635
  163. data/lib/action_view/locale/en.yml +0 -56
  164. data/lib/action_view/log_subscriber.rb +0 -30
  165. data/lib/action_view/lookup_context.rb +0 -248
  166. data/lib/action_view/model_naming.rb +0 -12
  167. data/lib/action_view/path_set.rb +0 -77
  168. data/lib/action_view/railtie.rb +0 -43
  169. data/lib/action_view/record_identifier.rb +0 -84
  170. data/lib/action_view/renderer/abstract_renderer.rb +0 -47
  171. data/lib/action_view/renderer/partial_renderer.rb +0 -500
  172. data/lib/action_view/renderer/renderer.rb +0 -50
  173. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
  174. data/lib/action_view/renderer/template_renderer.rb +0 -96
  175. data/lib/action_view/routing_url_for.rb +0 -107
  176. data/lib/action_view/tasks/dependencies.rake +0 -17
  177. data/lib/action_view/template.rb +0 -339
  178. data/lib/action_view/template/error.rb +0 -138
  179. data/lib/action_view/template/handlers.rb +0 -53
  180. data/lib/action_view/template/handlers/builder.rb +0 -26
  181. data/lib/action_view/template/handlers/erb.rb +0 -146
  182. data/lib/action_view/template/handlers/raw.rb +0 -11
  183. data/lib/action_view/template/resolver.rb +0 -340
  184. data/lib/action_view/template/text.rb +0 -34
  185. data/lib/action_view/template/types.rb +0 -57
  186. data/lib/action_view/test_case.rb +0 -270
  187. data/lib/action_view/testing/resolvers.rb +0 -50
  188. data/lib/action_view/vendor/html-scanner.rb +0 -20
  189. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  190. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  191. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  192. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  193. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  194. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
@@ -29,8 +29,11 @@ module ActionDispatch
29
29
  def call(env)
30
30
  @app.call(env)
31
31
  rescue Exception => exception
32
- raise exception if env['action_dispatch.show_exceptions'] == false
33
- render_exception(env, exception)
32
+ if env['action_dispatch.show_exceptions'] == false
33
+ raise exception
34
+ else
35
+ render_exception(env, exception)
36
+ end
34
37
  end
35
38
 
36
39
  private
@@ -57,7 +57,7 @@ module ActionDispatch
57
57
  cookies = cookies.split("\n")
58
58
 
59
59
  headers['Set-Cookie'] = cookies.map { |cookie|
60
- if cookie !~ /;\s+secure(;|$)/i
60
+ if cookie !~ /;\s*secure\s*(;|$)/i
61
61
  "#{cookie}; secure"
62
62
  else
63
63
  cookie
@@ -11,15 +11,13 @@ module ActionDispatch
11
11
  end
12
12
 
13
13
  def match?(path)
14
- path = unescape_path(path)
15
- return false unless path.valid_encoding?
14
+ path = path.dup
16
15
 
17
- full_path = path.empty? ? @root : File.join(@root,
18
- clean_path_info(escape_glob_chars(path)))
16
+ full_path = path.empty? ? @root : File.join(@root, escape_glob_chars(unescape_path(path)))
19
17
  paths = "#{full_path}#{ext}"
20
18
 
21
19
  matches = Dir[paths]
22
- match = matches.detect { |m| File.file?(m) && File.readable?(m) }
20
+ match = matches.detect { |m| File.file?(m) }
23
21
  if match
24
22
  match.sub!(@compiled_root, '')
25
23
  ::Rack::Utils.escape(match)
@@ -42,26 +40,8 @@ module ActionDispatch
42
40
  end
43
41
 
44
42
  def escape_glob_chars(path)
45
- path.gsub(/[*?{}\[\]\\]/, "\\\\\\&")
46
- end
47
-
48
- private
49
-
50
- PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
51
-
52
- def clean_path_info(path_info)
53
- parts = path_info.split PATH_SEPS
54
-
55
- clean = []
56
-
57
- parts.each do |part|
58
- next if part.empty? || part == '.'
59
- part == '..' ? clean.pop : clean << part
60
- end
61
-
62
- clean.unshift '/' if parts.empty? || parts.first.empty?
63
-
64
- ::File.join(*clean)
43
+ path.force_encoding('binary') if path.respond_to? :force_encoding
44
+ path.gsub(/[*?{}\[\]]/, "\\\\\\&")
65
45
  end
66
46
  end
67
47
 
@@ -0,0 +1,23 @@
1
+ <%
2
+ clean_params = @request.filtered_parameters.clone
3
+ clean_params.delete("action")
4
+ clean_params.delete("controller")
5
+
6
+ request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
7
+
8
+ def debug_hash(object)
9
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
10
+ end unless self.class.method_defined?(:debug_hash)
11
+ %>
12
+
13
+ Request parameters
14
+ <%= request_dump %>
15
+
16
+ Session dump
17
+ <%= debug_hash @request.session %>
18
+
19
+ Env dump
20
+ <%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %>
21
+
22
+ Response headers
23
+ <%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %>
@@ -0,0 +1,15 @@
1
+ <%
2
+ traces = { "Application Trace" => @application_trace,
3
+ "Framework Trace" => @framework_trace,
4
+ "Full Trace" => @full_trace }
5
+ %>
6
+
7
+ Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %>
8
+
9
+ <% traces.each do |name, trace| %>
10
+ <% if trace.any? %>
11
+ <%= name %>
12
+ <%= trace.join("\n") %>
13
+
14
+ <% end %>
15
+ <% end %>
@@ -8,7 +8,7 @@
8
8
  </header>
9
9
 
10
10
  <div id="container">
11
- <h2><%= @exception.message %></h2>
11
+ <h2><%= h @exception.message %></h2>
12
12
 
13
13
  <%= render template: "rescues/_source" %>
14
14
  <%= render template: "rescues/_trace" %>
@@ -3,5 +3,5 @@
3
3
  </header>
4
4
 
5
5
  <div id="container">
6
- <h2><%= @exception.message %></h2>
6
+ <h2><%= h @exception.message %></h2>
7
7
  </div>
@@ -0,0 +1,3 @@
1
+ Template is missing
2
+
3
+ <%= @exception.message %>
@@ -2,7 +2,7 @@
2
2
  <h1>Routing Error</h1>
3
3
  </header>
4
4
  <div id="container">
5
- <h2><%= @exception.message %></h2>
5
+ <h2><%= h @exception.message %></h2>
6
6
  <% unless @exception.failures.empty? %>
7
7
  <p>
8
8
  <h2>Failure reasons:</h2>
@@ -0,0 +1,11 @@
1
+ Routing Error
2
+
3
+ <%= @exception.message %>
4
+ <% unless @exception.failures.empty? %>
5
+ Failure reasons:
6
+ <% @exception.failures.each do |route, reason| %>
7
+ - <%= route.inspect.delete('\\') %></code> failed because <%= reason.downcase %>
8
+ <% end %>
9
+ <% end %>
10
+
11
+ <%= render template: "rescues/_trace", format: :text %>
@@ -10,7 +10,7 @@
10
10
  <p>
11
11
  Showing <i><%= @exception.file_name %></i> where line <b>#<%= @exception.line_number %></b> raised:
12
12
  </p>
13
- <pre><code><%= @exception.message %></code></pre>
13
+ <pre><code><%= h @exception.message %></code></pre>
14
14
 
15
15
  <div class="source">
16
16
  <div class="info">
@@ -0,0 +1,8 @@
1
+ <% @source_extract = @exception.source_extract(0, :html) %>
2
+ <%= @exception.original_exception.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
3
+
4
+ Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised:
5
+ <%= @exception.message %>
6
+ <%= @exception.sub_template_message %>
7
+ <%= render template: "rescues/_trace", format: :text %>
8
+ <%= render template: "rescues/_request_and_response", format: :text %>
@@ -2,5 +2,5 @@
2
2
  <h1>Unknown action</h1>
3
3
  </header>
4
4
  <div id="container">
5
- <h2><%= @exception.message %></h2>
5
+ <h2><%= h @exception.message %></h2>
6
6
  </div>
@@ -0,0 +1,3 @@
1
+ Unknown action
2
+
3
+ <%= @exception.message %>
@@ -89,8 +89,8 @@
89
89
  }
90
90
 
91
91
  // takes an array of elements with a data-regexp attribute and
92
- // passes their their parent <tr> into the callback function
93
- // if the regexp matchs a given path
92
+ // passes their parent <tr> into the callback function
93
+ // if the regexp matches a given path
94
94
  function eachElemsForPath(elems, path, func) {
95
95
  each(elems, function(e){
96
96
  var reg = e.getAttribute("data-regexp");
@@ -122,7 +122,7 @@
122
122
  // On key press perform a search for matching paths
123
123
  pathElem.onkeyup = function(e){
124
124
  var path = sanitizePath(pathElem.value),
125
- defaultText = '<tr><th colspan="4">Paths Matching (' + escape(path) + '):</th></tr>';
125
+ defaultText = '<tr><th colspan="4">Paths Matching (' + path + '):</th></tr>';
126
126
 
127
127
  // Clear out results section
128
128
  selectedSection.innerHTML= defaultText;
@@ -20,8 +20,7 @@ module ActionDispatch
20
20
  config.action_dispatch.default_headers = {
21
21
  'X-Frame-Options' => 'SAMEORIGIN',
22
22
  'X-XSS-Protection' => '1; mode=block',
23
- 'X-Content-Type-Options' => 'nosniff',
24
- 'X-UA-Compatible' => 'chrome=1'
23
+ 'X-Content-Type-Options' => 'nosniff'
25
24
  }
26
25
 
27
26
  config.eager_load_namespaces << ActionDispatch
@@ -7,6 +7,9 @@ module ActionDispatch
7
7
  ENV_SESSION_KEY = Rack::Session::Abstract::ENV_SESSION_KEY # :nodoc:
8
8
  ENV_SESSION_OPTIONS_KEY = Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY # :nodoc:
9
9
 
10
+ # Singleton object used to determine if an optional param wasn't specified
11
+ Unspecified = Object.new
12
+
10
13
  def self.create(store, env, default_options)
11
14
  session_was = find env
12
15
  session = Request::Session.new(store, env)
@@ -127,6 +130,15 @@ module ActionDispatch
127
130
  @delegate.delete key.to_s
128
131
  end
129
132
 
133
+ def fetch(key, default=Unspecified, &block)
134
+ load_for_read!
135
+ if default == Unspecified
136
+ @delegate.fetch(key.to_s, &block)
137
+ else
138
+ @delegate.fetch(key.to_s, default, &block)
139
+ end
140
+ end
141
+
130
142
  def inspect
131
143
  if loaded?
132
144
  super
@@ -0,0 +1,24 @@
1
+ module ActionDispatch
2
+ class Request < Rack::Request
3
+ class Utils # :nodoc:
4
+ class << self
5
+ # Remove nils from the params hash
6
+ def deep_munge(hash)
7
+ hash.each do |k, v|
8
+ case v
9
+ when Array
10
+ v.grep(Hash) { |x| deep_munge(x) }
11
+ v.compact!
12
+ hash[k] = nil if v.empty?
13
+ when Hash
14
+ deep_munge(v)
15
+ end
16
+ end
17
+
18
+ hash
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -1,7 +1,6 @@
1
1
  # encoding: UTF-8
2
2
  require 'active_support/core_ext/object/to_param'
3
3
  require 'active_support/core_ext/regexp'
4
- require 'active_support/dependencies/autoload'
5
4
 
6
5
  module ActionDispatch
7
6
  # The routing module provides URL rewriting in native Ruby. It's a way to
@@ -247,11 +246,13 @@ module ActionDispatch
247
246
  # Target specific controllers by prefixing the command with <tt>CONTROLLER=x</tt>.
248
247
  #
249
248
  module Routing
250
- autoload :Mapper, 'action_dispatch/routing/mapper'
251
- autoload :RouteSet, 'action_dispatch/routing/route_set'
252
- autoload :RoutesProxy, 'action_dispatch/routing/routes_proxy'
253
- autoload :UrlFor, 'action_dispatch/routing/url_for'
254
- autoload :PolymorphicRoutes, 'action_dispatch/routing/polymorphic_routes'
249
+ extend ActiveSupport::Autoload
250
+
251
+ autoload :Mapper
252
+ autoload :RouteSet
253
+ autoload :RoutesProxy
254
+ autoload :UrlFor
255
+ autoload :PolymorphicRoutes
255
256
 
256
257
  SEPARATORS = %w( / . ? ) #:nodoc:
257
258
  HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] #:nodoc:
@@ -69,7 +69,7 @@ module ActionDispatch
69
69
  end
70
70
 
71
71
  def internal?
72
- controller.to_s =~ %r{\Arails/(info|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}\z}
72
+ controller.to_s =~ %r{\Arails/(info|mailers|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}}
73
73
  end
74
74
 
75
75
  def engine?
@@ -194,9 +194,9 @@ module ActionDispatch
194
194
  end
195
195
 
196
196
  def widths(routes)
197
- [routes.map { |r| r[:name].length }.max || 0,
198
- routes.map { |r| r[:verb].length }.max || 0,
199
- routes.map { |r| r[:path].length }.max || 0]
197
+ [routes.map { |r| r[:name].length }.max,
198
+ routes.map { |r| r[:verb].length }.max,
199
+ routes.map { |r| r[:path].length }.max]
200
200
  end
201
201
  end
202
202
 
@@ -147,14 +147,16 @@ module ActionDispatch
147
147
  @defaults.merge!(options[:defaults]) if options[:defaults]
148
148
 
149
149
  options.each do |key, default|
150
- next if Regexp === default || IGNORE_OPTIONS.include?(key)
151
- @defaults[key] = default
150
+ unless Regexp === default || IGNORE_OPTIONS.include?(key)
151
+ @defaults[key] = default
152
+ end
152
153
  end
153
154
 
154
155
  if options[:constraints].is_a?(Hash)
155
156
  options[:constraints].each do |key, default|
156
- next unless URL_OPTIONS.include?(key) && (String === default || Fixnum === default)
157
- @defaults[key] ||= default
157
+ if URL_OPTIONS.include?(key) && (String === default || Fixnum === default)
158
+ @defaults[key] ||= default
159
+ end
158
160
  end
159
161
  end
160
162
 
@@ -166,19 +168,21 @@ module ActionDispatch
166
168
  end
167
169
 
168
170
  def normalize_conditions!
169
- @conditions.merge!(:path_info => path)
171
+ @conditions[:path_info] = path
170
172
 
171
173
  constraints.each do |key, condition|
172
- next if segment_keys.include?(key) || key == :controller
173
- @conditions[key] = condition
174
+ unless segment_keys.include?(key) || key == :controller
175
+ @conditions[key] = condition
176
+ end
174
177
  end
175
178
 
176
- @conditions[:required_defaults] = []
179
+ required_defaults = []
177
180
  options.each do |key, required_default|
178
- next if segment_keys.include?(key) || IGNORE_OPTIONS.include?(key)
179
- next if Regexp === required_default
180
- @conditions[:required_defaults] << key
181
+ unless segment_keys.include?(key) || IGNORE_OPTIONS.include?(key) || Regexp === required_default
182
+ required_defaults << key
183
+ end
181
184
  end
185
+ @conditions[:required_defaults] = required_defaults
182
186
 
183
187
  via_all = options.delete(:via) if options[:via] == :all
184
188
 
@@ -192,8 +196,7 @@ module ActionDispatch
192
196
  end
193
197
 
194
198
  if via = options[:via]
195
- list = Array(via).map { |m| m.to_s.dasherize.upcase }
196
- @conditions.merge!(:request_method => list)
199
+ @conditions[:request_method] = Array(via).map { |m| m.to_s.dasherize.upcase }
197
200
  end
198
201
  end
199
202
 
@@ -332,35 +335,18 @@ module ActionDispatch
332
335
  match '/', { :as => :root, :via => :get }.merge!(options)
333
336
  end
334
337
 
335
- # Matches a url pattern to one or more routes.
338
+ # Matches a url pattern to one or more routes. Any symbols in a pattern
339
+ # are interpreted as url query parameters and thus available as +params+
340
+ # in an action:
336
341
  #
337
- # You should not use the `match` method in your router
338
- # without specifying an HTTP method.
339
- #
340
- # If you want to expose your action to both GET and POST, use:
341
- #
342
342
  # # sets :controller, :action and :id in params
343
- # match ':controller/:action/:id', via: [:get, :post]
344
- #
345
- # Note that +:controller+, +:action+, +:id+ are interpreted as url query
346
- # parameters and thus available as +params+
347
- # in an action.
348
- #
349
- # If you want to expose your action to GET, use `get` in the router:
350
- #
351
- # Instead of:
352
- #
353
- # match ":controller/:action/:id"
354
- #
355
- # Do:
356
- #
357
- # get ":controller/:action/:id"
343
+ # match ':controller/:action/:id'
358
344
  #
359
345
  # Two of these symbols are special, +:controller+ maps to the controller
360
346
  # and +:action+ to the controller's action. A pattern can also map
361
347
  # wildcard segments (globs) to params:
362
348
  #
363
- # get 'songs/*category/:title', to: 'songs#show'
349
+ # match 'songs/*category/:title', to: 'songs#show'
364
350
  #
365
351
  # # 'songs/rock/classic/stairway-to-heaven' sets
366
352
  # # params[:category] = 'rock/classic'
@@ -369,20 +355,21 @@ module ActionDispatch
369
355
  # When a pattern points to an internal route, the route's +:action+ and
370
356
  # +:controller+ should be set in options or hash shorthand. Examples:
371
357
  #
372
- # match 'photos/:id' => 'photos#show', via: [:get]
373
- # match 'photos/:id', to: 'photos#show', via: [:get]
374
- # match 'photos/:id', controller: 'photos', action: 'show', via: [:get]
358
+ # match 'photos/:id' => 'photos#show'
359
+ # match 'photos/:id', to: 'photos#show'
360
+ # match 'photos/:id', controller: 'photos', action: 'show'
375
361
  #
376
362
  # A pattern can also point to a +Rack+ endpoint i.e. anything that
377
363
  # responds to +call+:
378
364
  #
379
- # match 'photos/:id', to: lambda {|hash| [200, {}, ["Coming soon"]] }, via: [:get]
380
- # match 'photos/:id', to: PhotoRackApp, via: [:get]
365
+ # match 'photos/:id', to: lambda {|hash| [200, {}, ["Coming soon"]] }
366
+ # match 'photos/:id', to: PhotoRackApp
381
367
  # # Yes, controller actions are just rack endpoints
382
- # match 'photos/:id', to: PhotosController.action(:show), via: [:get]
368
+ # match 'photos/:id', to: PhotosController.action(:show)
383
369
  #
384
- # Because request various HTTP verbs with a single action has security
385
- # implications, is recommendable use HttpHelpers[rdoc-ref:HttpHelpers]
370
+ # Because requesting various HTTP verbs with a single action has security
371
+ # implications, you must either specify the actions in
372
+ # the via options or use one of the HtttpHelpers[rdoc-ref:HttpHelpers]
386
373
  # instead +match+
387
374
  #
388
375
  # === Options
@@ -395,19 +382,13 @@ module ActionDispatch
395
382
  # [:action]
396
383
  # The route's action.
397
384
  #
398
- # [:param]
399
- # Overrides the default resource identifier `:id` (name of the
400
- # dynamic segment used to generate the routes).
401
- # You can access that segment from your controller using
402
- # <tt>params[<:param>]</tt>.
403
- #
404
385
  # [:path]
405
386
  # The path prefix for the routes.
406
387
  #
407
388
  # [:module]
408
389
  # The namespace for :controller.
409
390
  #
410
- # match 'path', to: 'c#a', module: 'sekret', controller: 'posts', via: [:get]
391
+ # match 'path', to: 'c#a', module: 'sekret', controller: 'posts'
411
392
  # # => Sekret::PostsController
412
393
  #
413
394
  # See <tt>Scoping#namespace</tt> for its scope equivalent.
@@ -426,9 +407,9 @@ module ActionDispatch
426
407
  # Points to a +Rack+ endpoint. Can be an object that responds to
427
408
  # +call+ or a string representing a controller's action.
428
409
  #
429
- # match 'path', to: 'controller#action', via: [:get]
430
- # match 'path', to: lambda { |env| [200, {}, ["Success!"]] }, via: [:get]
431
- # match 'path', to: RackApp, via: [:get]
410
+ # match 'path', to: 'controller#action'
411
+ # match 'path', to: lambda { |env| [200, {}, ["Success!"]] }
412
+ # match 'path', to: RackApp
432
413
  #
433
414
  # [:on]
434
415
  # Shorthand for wrapping routes in a specific RESTful context. Valid
@@ -453,14 +434,14 @@ module ActionDispatch
453
434
  # other than path can also be specified with any object
454
435
  # that responds to <tt>===</tt> (eg. String, Array, Range, etc.).
455
436
  #
456
- # match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }, via: [:get]
437
+ # match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }
457
438
  #
458
- # match 'json_only', constraints: { format: 'json' }, via: [:get]
439
+ # match 'json_only', constraints: { format: 'json' }
459
440
  #
460
- # class Blacklist
441
+ # class Whitelist
461
442
  # def matches?(request) request.remote_ip == '1.2.3.4' end
462
443
  # end
463
- # match 'path', to: 'c#a', constraints: Blacklist.new, via: [:get]
444
+ # match 'path', to: 'c#a', constraints: Whitelist.new
464
445
  #
465
446
  # See <tt>Scoping#constraints</tt> for more examples with its scope
466
447
  # equivalent.
@@ -469,7 +450,7 @@ module ActionDispatch
469
450
  # Sets defaults for parameters
470
451
  #
471
452
  # # Sets params[:format] to 'jpg' by default
472
- # match 'path', to: 'c#a', defaults: { format: 'jpg' }, via: [:get]
453
+ # match 'path', to: 'c#a', defaults: { format: 'jpg' }
473
454
  #
474
455
  # See <tt>Scoping#defaults</tt> for its scope equivalent.
475
456
  #
@@ -478,7 +459,7 @@ module ActionDispatch
478
459
  # false, the pattern matches any request prefixed with the given path.
479
460
  #
480
461
  # # Matches any request starting with 'path'
481
- # match 'path', to: 'c#a', anchor: false, via: [:get]
462
+ # match 'path', to: 'c#a', anchor: false
482
463
  #
483
464
  # [:format]
484
465
  # Allows you to specify the default value for optional +format+
@@ -521,11 +502,12 @@ module ActionDispatch
521
502
  raise "A rack application must be specified" unless path
522
503
 
523
504
  options[:as] ||= app_name(app)
505
+ target_as = name_for_action(options[:as], path)
524
506
  options[:via] ||= :all
525
507
 
526
508
  match(path, options.merge(:to => app, :anchor => false, :format => false))
527
509
 
528
- define_generate_prefix(app, options[:as])
510
+ define_generate_prefix(app, target_as)
529
511
  self
530
512
  end
531
513
 
@@ -720,11 +702,6 @@ module ActionDispatch
720
702
  options[:path] = args.flatten.join('/') if args.any?
721
703
  options[:constraints] ||= {}
722
704
 
723
- unless nested_scope?
724
- options[:shallow_path] ||= options[:path] if options.key?(:path)
725
- options[:shallow_prefix] ||= options[:as] if options.key?(:as)
726
- end
727
-
728
705
  if options[:constraints].is_a?(Hash)
729
706
  defaults = options[:constraints].select do
730
707
  |k, v| URL_OPTIONS.include?(k) && (v.is_a?(String) || v.is_a?(Fixnum))
@@ -806,16 +783,9 @@ module ActionDispatch
806
783
  # end
807
784
  def namespace(path, options = {})
808
785
  path = path.to_s
809
-
810
- defaults = {
811
- module: path,
812
- path: options.fetch(:path, path),
813
- as: options.fetch(:as, path),
814
- shallow_path: options.fetch(:path, path),
815
- shallow_prefix: options.fetch(:as, path)
816
- }
817
-
818
- scope(defaults.merge!(options)) { yield }
786
+ options = { :path => path, :as => path, :module => path,
787
+ :shallow_path => path, :shallow_prefix => path }.merge!(options)
788
+ scope(options) { yield }
819
789
  end
820
790
 
821
791
  # === Parameter Restriction
@@ -1004,7 +974,6 @@ module ActionDispatch
1004
974
  @as = options[:as]
1005
975
  @param = (options[:param] || :id).to_sym
1006
976
  @options = options
1007
- @shallow = false
1008
977
  end
1009
978
 
1010
979
  def default_actions
@@ -1065,13 +1034,6 @@ module ActionDispatch
1065
1034
  "#{path}/:#{nested_param}"
1066
1035
  end
1067
1036
 
1068
- def shallow=(value)
1069
- @shallow = value
1070
- end
1071
-
1072
- def shallow?
1073
- @shallow
1074
- end
1075
1037
  end
1076
1038
 
1077
1039
  class SingletonResource < Resource #:nodoc:
@@ -1111,18 +1073,18 @@ module ActionDispatch
1111
1073
  # a singular resource to map /profile (rather than /profile/:id) to
1112
1074
  # the show action:
1113
1075
  #
1114
- # resource :geocoder
1076
+ # resource :profile
1115
1077
  #
1116
1078
  # creates six different routes in your application, all mapping to
1117
- # the +GeoCoders+ controller (note that the controller is named after
1079
+ # the +Profiles+ controller (note that the controller is named after
1118
1080
  # the plural):
1119
1081
  #
1120
- # GET /geocoder/new
1121
- # POST /geocoder
1122
- # GET /geocoder
1123
- # GET /geocoder/edit
1124
- # PATCH/PUT /geocoder
1125
- # DELETE /geocoder
1082
+ # GET /profile/new
1083
+ # POST /profile
1084
+ # GET /profile
1085
+ # GET /profile/edit
1086
+ # PATCH/PUT /profile
1087
+ # DELETE /profile
1126
1088
  #
1127
1089
  # === Options
1128
1090
  # Takes same options as +resources+.
@@ -1352,10 +1314,8 @@ module ActionDispatch
1352
1314
  end
1353
1315
 
1354
1316
  with_scope_level(:member) do
1355
- if shallow?
1356
- shallow_scope(parent_resource.member_scope) { yield }
1357
- else
1358
- scope(parent_resource.member_scope) { yield }
1317
+ scope(parent_resource.member_scope) do
1318
+ yield
1359
1319
  end
1360
1320
  end
1361
1321
  end
@@ -1378,8 +1338,16 @@ module ActionDispatch
1378
1338
  end
1379
1339
 
1380
1340
  with_scope_level(:nested) do
1381
- if shallow? && shallow_nesting_depth >= 1
1382
- shallow_scope(parent_resource.nested_scope, nested_options) { yield }
1341
+ if shallow?
1342
+ with_exclusive_scope do
1343
+ if @scope[:shallow_path].blank?
1344
+ scope(parent_resource.nested_scope, nested_options) { yield }
1345
+ else
1346
+ scope(@scope[:shallow_path], :as => @scope[:shallow_prefix]) do
1347
+ scope(parent_resource.nested_scope, nested_options) { yield }
1348
+ end
1349
+ end
1350
+ end
1383
1351
  else
1384
1352
  scope(parent_resource.nested_scope, nested_options) { yield }
1385
1353
  end
@@ -1396,7 +1364,7 @@ module ActionDispatch
1396
1364
  end
1397
1365
 
1398
1366
  def shallow
1399
- scope(:shallow => true) do
1367
+ scope(:shallow => true, :shallow_path => @scope[:path]) do
1400
1368
  yield
1401
1369
  end
1402
1370
  end
@@ -1516,13 +1484,6 @@ module ActionDispatch
1516
1484
  return true
1517
1485
  end
1518
1486
 
1519
- if options.delete(:shallow)
1520
- shallow do
1521
- send(method, resources.pop, options, &block)
1522
- end
1523
- return true
1524
- end
1525
-
1526
1487
  if resource_scope?
1527
1488
  nested { send(method, resources.pop, options, &block) }
1528
1489
  return true
@@ -1567,10 +1528,6 @@ module ActionDispatch
1567
1528
  RESOURCE_METHOD_SCOPES.include? @scope[:scope_level]
1568
1529
  end
1569
1530
 
1570
- def nested_scope? #:nodoc:
1571
- @scope[:scope_level] == :nested
1572
- end
1573
-
1574
1531
  def with_exclusive_scope
1575
1532
  begin
1576
1533
  old_name_prefix, old_path = @scope[:as], @scope[:path]
@@ -1584,24 +1541,21 @@ module ActionDispatch
1584
1541
  end
1585
1542
  end
1586
1543
 
1587
- def with_scope_level(kind)
1544
+ def with_scope_level(kind, resource = parent_resource)
1588
1545
  old, @scope[:scope_level] = @scope[:scope_level], kind
1546
+ old_resource, @scope[:scope_level_resource] = @scope[:scope_level_resource], resource
1589
1547
  yield
1590
1548
  ensure
1591
1549
  @scope[:scope_level] = old
1550
+ @scope[:scope_level_resource] = old_resource
1592
1551
  end
1593
1552
 
1594
1553
  def resource_scope(kind, resource) #:nodoc:
1595
- resource.shallow = @scope[:shallow]
1596
- old_resource, @scope[:scope_level_resource] = @scope[:scope_level_resource], resource
1597
- @nesting.push(resource)
1598
-
1599
- with_scope_level(kind) do
1600
- scope(parent_resource.resource_scope) { yield }
1554
+ with_scope_level(kind, resource) do
1555
+ scope(parent_resource.resource_scope) do
1556
+ yield
1557
+ end
1601
1558
  end
1602
- ensure
1603
- @nesting.pop
1604
- @scope[:scope_level_resource] = old_resource
1605
1559
  end
1606
1560
 
1607
1561
  def nested_options #:nodoc:
@@ -1613,14 +1567,6 @@ module ActionDispatch
1613
1567
  options
1614
1568
  end
1615
1569
 
1616
- def nesting_depth #:nodoc:
1617
- @nesting.size
1618
- end
1619
-
1620
- def shallow_nesting_depth #:nodoc:
1621
- @nesting.select(&:shallow?).size
1622
- end
1623
-
1624
1570
  def param_constraint? #:nodoc:
1625
1571
  @scope[:constraints] && @scope[:constraints][parent_resource.param].is_a?(Regexp)
1626
1572
  end
@@ -1633,20 +1579,18 @@ module ActionDispatch
1633
1579
  flag && resource_method_scope? && CANONICAL_ACTIONS.include?(action.to_s)
1634
1580
  end
1635
1581
 
1636
- def shallow_scope(path, options = {}) #:nodoc:
1637
- old_name_prefix, old_path = @scope[:as], @scope[:path]
1638
- @scope[:as], @scope[:path] = @scope[:shallow_prefix], @scope[:shallow_path]
1639
-
1640
- scope(path, options) { yield }
1641
- ensure
1642
- @scope[:as], @scope[:path] = old_name_prefix, old_path
1582
+ def shallow_scoping? #:nodoc:
1583
+ shallow? && @scope[:scope_level] == :member
1643
1584
  end
1644
1585
 
1645
1586
  def path_for_action(action, path) #:nodoc:
1587
+ prefix = shallow_scoping? ?
1588
+ "#{@scope[:shallow_path]}/#{parent_resource.shallow_scope}" : @scope[:path]
1589
+
1646
1590
  if canonical_action?(action, path.blank?)
1647
- @scope[:path].to_s
1591
+ prefix.to_s
1648
1592
  else
1649
- "#{@scope[:path]}/#{action_path(action, path)}"
1593
+ "#{prefix}/#{action_path(action, path)}"
1650
1594
  end
1651
1595
  end
1652
1596
 
@@ -1683,7 +1627,7 @@ module ActionDispatch
1683
1627
  when :new
1684
1628
  [prefix, :new, name_prefix, member_name]
1685
1629
  when :member
1686
- [prefix, name_prefix, member_name]
1630
+ [prefix, shallow_scoping? ? @scope[:shallow_prefix] : name_prefix, member_name]
1687
1631
  when :root
1688
1632
  [name_prefix, collection_name, prefix]
1689
1633
  else
@@ -1824,7 +1768,6 @@ module ActionDispatch
1824
1768
  @set = set
1825
1769
  @scope = { :path_names => @set.resources_path_names }
1826
1770
  @concerns = {}
1827
- @nesting = []
1828
1771
  end
1829
1772
 
1830
1773
  include Base