actionpack 4.2.11.3 → 5.0.7.2

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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +890 -384
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/abstract_controller/base.rb +28 -38
  6. data/lib/{action_controller → abstract_controller}/caching/fragments.rb +51 -11
  7. data/lib/abstract_controller/caching.rb +62 -0
  8. data/lib/abstract_controller/callbacks.rb +54 -19
  9. data/lib/abstract_controller/collector.rb +4 -9
  10. data/lib/abstract_controller/error.rb +4 -0
  11. data/lib/abstract_controller/helpers.rb +4 -3
  12. data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
  13. data/lib/abstract_controller/rendering.rb +28 -18
  14. data/lib/abstract_controller/translation.rb +8 -7
  15. data/lib/abstract_controller.rb +6 -2
  16. data/lib/action_controller/api/api_rendering.rb +14 -0
  17. data/lib/action_controller/api.rb +147 -0
  18. data/lib/action_controller/base.rb +14 -11
  19. data/lib/action_controller/caching.rb +13 -58
  20. data/lib/action_controller/form_builder.rb +48 -0
  21. data/lib/action_controller/log_subscriber.rb +3 -10
  22. data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
  23. data/lib/action_controller/metal/conditional_get.rb +106 -34
  24. data/lib/action_controller/metal/cookies.rb +1 -3
  25. data/lib/action_controller/metal/data_streaming.rb +14 -34
  26. data/lib/action_controller/metal/etag_with_template_digest.rb +8 -2
  27. data/lib/action_controller/metal/exceptions.rb +11 -6
  28. data/lib/action_controller/metal/force_ssl.rb +11 -11
  29. data/lib/action_controller/metal/head.rb +14 -8
  30. data/lib/action_controller/metal/helpers.rb +15 -6
  31. data/lib/action_controller/metal/http_authentication.rb +44 -35
  32. data/lib/action_controller/metal/implicit_render.rb +61 -6
  33. data/lib/action_controller/metal/instrumentation.rb +5 -5
  34. data/lib/action_controller/metal/live.rb +71 -88
  35. data/lib/action_controller/metal/mime_responds.rb +27 -42
  36. data/lib/action_controller/metal/params_wrapper.rb +9 -9
  37. data/lib/action_controller/metal/redirecting.rb +32 -9
  38. data/lib/action_controller/metal/renderers.rb +83 -40
  39. data/lib/action_controller/metal/rendering.rb +38 -6
  40. data/lib/action_controller/metal/request_forgery_protection.rb +126 -48
  41. data/lib/action_controller/metal/rescue.rb +3 -12
  42. data/lib/action_controller/metal/streaming.rb +4 -4
  43. data/lib/action_controller/metal/strong_parameters.rb +527 -134
  44. data/lib/action_controller/metal/testing.rb +1 -12
  45. data/lib/action_controller/metal/url_for.rb +12 -5
  46. data/lib/action_controller/metal.rb +88 -63
  47. data/lib/action_controller/railtie.rb +11 -7
  48. data/lib/action_controller/renderer.rb +113 -0
  49. data/lib/action_controller/template_assertions.rb +9 -0
  50. data/lib/action_controller/test_case.rb +311 -374
  51. data/lib/action_controller.rb +12 -9
  52. data/lib/action_dispatch/http/cache.rb +73 -34
  53. data/lib/action_dispatch/http/filter_parameters.rb +16 -12
  54. data/lib/action_dispatch/http/filter_redirect.rb +7 -8
  55. data/lib/action_dispatch/http/headers.rb +45 -14
  56. data/lib/action_dispatch/http/mime_negotiation.rb +42 -23
  57. data/lib/action_dispatch/http/mime_type.rb +126 -90
  58. data/lib/action_dispatch/http/mime_types.rb +3 -4
  59. data/lib/action_dispatch/http/parameter_filter.rb +19 -9
  60. data/lib/action_dispatch/http/parameters.rb +70 -40
  61. data/lib/action_dispatch/http/request.rb +144 -89
  62. data/lib/action_dispatch/http/response.rb +215 -102
  63. data/lib/action_dispatch/http/upload.rb +6 -2
  64. data/lib/action_dispatch/http/url.rb +117 -8
  65. data/lib/action_dispatch/journey/formatter.rb +47 -30
  66. data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
  67. data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
  68. data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
  69. data/lib/action_dispatch/journey/nodes/node.rb +14 -4
  70. data/lib/action_dispatch/journey/parser.rb +2 -0
  71. data/lib/action_dispatch/journey/parser_extras.rb +8 -2
  72. data/lib/action_dispatch/journey/path/pattern.rb +38 -42
  73. data/lib/action_dispatch/journey/route.rb +88 -26
  74. data/lib/action_dispatch/journey/router/utils.rb +5 -5
  75. data/lib/action_dispatch/journey/router.rb +8 -10
  76. data/lib/action_dispatch/journey/routes.rb +14 -15
  77. data/lib/action_dispatch/journey/visitors.rb +89 -44
  78. data/lib/action_dispatch/middleware/callbacks.rb +10 -1
  79. data/lib/action_dispatch/middleware/cookies.rb +188 -134
  80. data/lib/action_dispatch/middleware/debug_exceptions.rb +128 -49
  81. data/lib/action_dispatch/middleware/debug_locks.rb +122 -0
  82. data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -21
  83. data/lib/action_dispatch/middleware/executor.rb +19 -0
  84. data/lib/action_dispatch/middleware/flash.rb +66 -45
  85. data/lib/action_dispatch/middleware/params_parser.rb +32 -46
  86. data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
  87. data/lib/action_dispatch/middleware/reloader.rb +14 -58
  88. data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
  89. data/lib/action_dispatch/middleware/request_id.rb +11 -6
  90. data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
  91. data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
  92. data/lib/action_dispatch/middleware/session/cookie_store.rb +30 -24
  93. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
  94. data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
  95. data/lib/action_dispatch/middleware/ssl.rb +124 -36
  96. data/lib/action_dispatch/middleware/stack.rb +44 -40
  97. data/lib/action_dispatch/middleware/static.rb +51 -35
  98. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  99. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  101. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  102. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  103. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -63
  104. data/lib/action_dispatch/railtie.rb +2 -2
  105. data/lib/action_dispatch/request/session.rb +69 -33
  106. data/lib/action_dispatch/request/utils.rb +51 -19
  107. data/lib/action_dispatch/routing/inspector.rb +32 -43
  108. data/lib/action_dispatch/routing/mapper.rb +515 -348
  109. data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
  110. data/lib/action_dispatch/routing/redirection.rb +5 -4
  111. data/lib/action_dispatch/routing/route_set.rb +148 -240
  112. data/lib/action_dispatch/routing/url_for.rb +27 -10
  113. data/lib/action_dispatch/routing.rb +17 -13
  114. data/lib/action_dispatch/testing/assertion_response.rb +45 -0
  115. data/lib/action_dispatch/testing/assertions/response.rb +38 -20
  116. data/lib/action_dispatch/testing/assertions/routing.rb +16 -12
  117. data/lib/action_dispatch/testing/assertions.rb +1 -1
  118. data/lib/action_dispatch/testing/integration.rb +377 -149
  119. data/lib/action_dispatch/testing/request_encoder.rb +53 -0
  120. data/lib/action_dispatch/testing/test_process.rb +24 -20
  121. data/lib/action_dispatch/testing/test_request.rb +22 -31
  122. data/lib/action_dispatch/testing/test_response.rb +12 -4
  123. data/lib/action_dispatch.rb +4 -1
  124. data/lib/action_pack/gem_version.rb +4 -4
  125. data/lib/action_pack.rb +1 -1
  126. metadata +32 -34
  127. data/lib/action_controller/metal/hide_actions.rb +0 -40
  128. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  129. data/lib/action_controller/middleware.rb +0 -39
  130. data/lib/action_controller/model_naming.rb +0 -12
  131. data/lib/action_dispatch/journey/backwards.rb +0 -5
  132. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  133. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  134. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  135. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
  136. /data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
@@ -81,92 +81,87 @@
81
81
  </table>
82
82
 
83
83
  <script type='text/javascript'>
84
- // Iterates each element through a function
85
- function each(elems, func) {
86
- if (!elems instanceof Array) { elems = [elems]; }
87
- for (var i = 0, len = elems.length; i < len; i++) {
88
- func(elems[i]);
89
- }
90
- }
91
-
92
- // Sets innerHTML for an element
93
- function setContent(elem, text) {
94
- elem.innerHTML = text;
95
- }
84
+ // support forEarch iterator on NodeList
85
+ NodeList.prototype.forEach = Array.prototype.forEach;
96
86
 
97
87
  // Enables path search functionality
98
88
  function setupMatchPaths() {
99
- // Check if the user input (sanitized as a path) matches the regexp data attribute
100
- function checkExactMatch(section, elem, value) {
101
- var string = sanitizePath(value),
102
- regexp = elem.getAttribute("data-regexp");
103
-
104
- showMatch(string, regexp, section, elem);
89
+ // Check if there are any matched results in a section
90
+ function checkNoMatch(section, noMatchText) {
91
+ if (section.children.length <= 1) {
92
+ section.innerHTML += noMatchText;
93
+ }
105
94
  }
106
95
 
107
- // Check if the route path data attribute contains the user input
108
- function checkFuzzyMatch(section, elem, value) {
109
- var string = elem.getAttribute("data-route-path"),
110
- regexp = value;
111
-
112
- showMatch(string, regexp, section, elem);
96
+ // get JSON from url and invoke callback with result
97
+ function getJSON(url, success) {
98
+ var xhr = new XMLHttpRequest();
99
+ xhr.open('GET', url);
100
+ xhr.onload = function() {
101
+ if (this.status == 200)
102
+ success(JSON.parse(this.response));
103
+ };
104
+ xhr.send();
113
105
  }
114
106
 
115
- // Display the parent <tr> element in the appropriate section when there's a match
116
- function showMatch(string, regexp, section, elem) {
117
- if(string.match(RegExp(regexp))) {
118
- section.appendChild(elem.parentNode.cloneNode(true));
107
+ function delayedKeyup(input, callback) {
108
+ var timeout;
109
+ input.onkeyup = function(){
110
+ if (timeout) clearTimeout(timeout);
111
+ timeout = setTimeout(callback, 300);
119
112
  }
120
113
  }
121
114
 
122
- // Check if there are any matched results in a section
123
- function checkNoMatch(section, defaultText, noMatchText) {
124
- if (section.innerHTML === defaultText) {
125
- setContent(section, defaultText + noMatchText);
126
- }
127
- }
128
-
129
- // Ensure path always starts with a slash "/" and remove params or fragments
115
+ // remove params or fragments
130
116
  function sanitizePath(path) {
131
- var path = path.charAt(0) == '/' ? path : "/" + path;
132
- return path.replace(/\#.*|\?.*/, '');
117
+ return path.replace(/[#?].*/, '');
133
118
  }
134
119
 
135
- var regexpElems = document.querySelectorAll('#route_table [data-regexp]'),
136
- searchElem = document.querySelector('#search'),
137
- exactMatches = document.querySelector('#exact_matches'),
138
- fuzzyMatches = document.querySelector('#fuzzy_matches');
120
+ var pathElements = document.querySelectorAll('#route_table [data-route-path]'),
121
+ searchElem = document.querySelector('#search'),
122
+ exactSection = document.querySelector('#exact_matches'),
123
+ fuzzySection = document.querySelector('#fuzzy_matches');
139
124
 
140
125
  // Remove matches when no search value is present
141
126
  searchElem.onblur = function(e) {
142
127
  if (searchElem.value === "") {
143
- setContent(exactMatches, "");
144
- setContent(fuzzyMatches, "");
128
+ exactSection.innerHTML = "";
129
+ fuzzySection.innerHTML = "";
145
130
  }
146
131
  }
147
132
 
148
133
  // On key press perform a search for matching paths
149
- searchElem.onkeyup = function(e){
150
- var userInput = searchElem.value,
151
- defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + escape(sanitizePath(userInput)) +'):</th></tr>',
152
- defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + escape(userInput) +'):</th></tr>',
134
+ delayedKeyup(searchElem, function() {
135
+ var path = sanitizePath(searchElem.value),
136
+ defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + path +'):</th></tr>',
137
+ defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + path +'):</th></tr>',
153
138
  noExactMatch = '<tr><th colspan="4">No Exact Matches Found</th></tr>',
154
139
  noFuzzyMatch = '<tr><th colspan="4">No Fuzzy Matches Found</th></tr>';
155
140
 
156
- // Clear out results section
157
- setContent(exactMatches, defaultExactMatch);
158
- setContent(fuzzyMatches, defaultFuzzyMatch);
141
+ if (!path)
142
+ return searchElem.onblur();
159
143
 
160
- // Display exact matches and fuzzy matches
161
- each(regexpElems, function(elem) {
162
- checkExactMatch(exactMatches, elem, userInput);
163
- checkFuzzyMatch(fuzzyMatches, elem, userInput);
164
- })
144
+ getJSON('/rails/info/routes?path=' + path, function(matches){
145
+ // Clear out results section
146
+ exactSection.innerHTML = defaultExactMatch;
147
+ fuzzySection.innerHTML = defaultFuzzyMatch;
165
148
 
166
- // Display 'No Matches' message when no matches are found
167
- checkNoMatch(exactMatches, defaultExactMatch, noExactMatch);
168
- checkNoMatch(fuzzyMatches, defaultFuzzyMatch, noFuzzyMatch);
169
- }
149
+ // Display exact matches and fuzzy matches
150
+ pathElements.forEach(function(elem) {
151
+ var elemPath = elem.getAttribute('data-route-path');
152
+
153
+ if (matches['exact'].indexOf(elemPath) != -1)
154
+ exactSection.appendChild(elem.parentNode.cloneNode(true));
155
+
156
+ if (matches['fuzzy'].indexOf(elemPath) != -1)
157
+ fuzzySection.appendChild(elem.parentNode.cloneNode(true));
158
+ })
159
+
160
+ // Display 'No Matches' message when no matches are found
161
+ checkNoMatch(exactSection, noExactMatch);
162
+ checkNoMatch(fuzzySection, noFuzzyMatch);
163
+ })
164
+ })
170
165
  }
171
166
 
172
167
  // Enables functionality to toggle between `_path` and `_url` helper suffixes
@@ -174,19 +169,20 @@
174
169
 
175
170
  // Sets content for each element
176
171
  function setValOn(elems, val) {
177
- each(elems, function(elem) {
178
- setContent(elem, val);
172
+ elems.forEach(function(elem) {
173
+ elem.innerHTML = val;
179
174
  });
180
175
  }
181
176
 
182
177
  // Sets onClick event for each element
183
178
  function onClick(elems, func) {
184
- each(elems, function(elem) {
179
+ elems.forEach(function(elem) {
185
180
  elem.onclick = func;
186
181
  });
187
182
  }
188
183
 
189
184
  var toggleLinks = document.querySelectorAll('#route_table [data-route-helper]');
185
+
190
186
  onClick(toggleLinks, function(){
191
187
  var helperTxt = this.getAttribute("data-route-helper"),
192
188
  helperElems = document.querySelectorAll('[data-route-name] span.helper');
@@ -39,9 +39,9 @@ module ActionDispatch
39
39
  config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil?
40
40
  ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie
41
41
 
42
- ActionDispatch.test_app = app
42
+ ActionDispatch::Reloader.default_reloader = app.reloader
43
43
 
44
- ActionDispatch::Routing::RouteSet.relative_url_root = app.config.relative_url_root
44
+ ActionDispatch.test_app = app
45
45
  end
46
46
  end
47
47
  end
@@ -1,56 +1,56 @@
1
1
  require 'rack/session/abstract/id'
2
2
 
3
3
  module ActionDispatch
4
- class Request < Rack::Request
4
+ class Request
5
5
  # Session is responsible for lazily loading the session from store.
6
6
  class Session # :nodoc:
7
- ENV_SESSION_KEY = Rack::Session::Abstract::ENV_SESSION_KEY # :nodoc:
8
- ENV_SESSION_OPTIONS_KEY = Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY # :nodoc:
7
+ ENV_SESSION_KEY = Rack::RACK_SESSION # :nodoc:
8
+ ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS # :nodoc:
9
9
 
10
10
  # Singleton object used to determine if an optional param wasn't specified
11
11
  Unspecified = Object.new
12
12
 
13
- def self.create(store, env, default_options)
14
- session_was = find env
15
- session = Request::Session.new(store, env)
13
+ # Creates a session hash, merging the properties of the previous session if any
14
+ def self.create(store, req, default_options)
15
+ session_was = find req
16
+ session = Request::Session.new(store, req)
16
17
  session.merge! session_was if session_was
17
18
 
18
- set(env, session)
19
- Options.set(env, Request::Session::Options.new(store, env, default_options))
19
+ set(req, session)
20
+ Options.set(req, Request::Session::Options.new(store, default_options))
20
21
  session
21
22
  end
22
23
 
23
- def self.find(env)
24
- env[ENV_SESSION_KEY]
24
+ def self.find(req)
25
+ req.get_header ENV_SESSION_KEY
25
26
  end
26
27
 
27
- def self.set(env, session)
28
- env[ENV_SESSION_KEY] = session
28
+ def self.set(req, session)
29
+ req.set_header ENV_SESSION_KEY, session
29
30
  end
30
31
 
31
32
  class Options #:nodoc:
32
- def self.set(env, options)
33
- env[ENV_SESSION_OPTIONS_KEY] = options
33
+ def self.set(req, options)
34
+ req.set_header ENV_SESSION_OPTIONS_KEY, options
34
35
  end
35
36
 
36
- def self.find(env)
37
- env[ENV_SESSION_OPTIONS_KEY]
37
+ def self.find(req)
38
+ req.get_header ENV_SESSION_OPTIONS_KEY
38
39
  end
39
40
 
40
- def initialize(by, env, default_options)
41
+ def initialize(by, default_options)
41
42
  @by = by
42
- @env = env
43
43
  @delegate = default_options.dup
44
44
  end
45
45
 
46
46
  def [](key)
47
- if key == :id
48
- @delegate.fetch(key) {
49
- @delegate[:id] = @by.send(:extract_session_id, @env)
50
- }
51
- else
52
- @delegate[key]
53
- end
47
+ @delegate[key]
48
+ end
49
+
50
+ def id(req)
51
+ @delegate.fetch(:id) {
52
+ @by.send(:extract_session_id, req)
53
+ }
54
54
  end
55
55
 
56
56
  def []=(k,v); @delegate[k] = v; end
@@ -58,38 +58,40 @@ module ActionDispatch
58
58
  def values_at(*args); @delegate.values_at(*args); end
59
59
  end
60
60
 
61
- def initialize(by, env)
61
+ def initialize(by, req)
62
62
  @by = by
63
- @env = env
63
+ @req = req
64
64
  @delegate = {}
65
65
  @loaded = false
66
66
  @exists = nil # we haven't checked yet
67
67
  end
68
68
 
69
69
  def id
70
- options[:id]
70
+ options.id(@req)
71
71
  end
72
72
 
73
73
  def options
74
- Options.find @env
74
+ Options.find @req
75
75
  end
76
76
 
77
77
  def destroy
78
78
  clear
79
79
  options = self.options || {}
80
- new_sid = @by.send(:destroy_session, @env, options[:id], options)
81
- options[:id] = new_sid # Reset session id with a new value or nil
80
+ @by.send(:delete_session, @req, options.id(@req), options)
82
81
 
83
82
  # Load the new sid to be written with the response
84
83
  @loaded = false
85
84
  load_for_write!
86
85
  end
87
86
 
87
+ # Returns value of the key stored in the session or
88
+ # nil if the given key is not found in the session.
88
89
  def [](key)
89
90
  load_for_read!
90
91
  @delegate[key.to_s]
91
92
  end
92
93
 
94
+ # Returns true if the session has the given key or false.
93
95
  def has_key?(key)
94
96
  load_for_read!
95
97
  @delegate.key?(key.to_s)
@@ -97,39 +99,69 @@ module ActionDispatch
97
99
  alias :key? :has_key?
98
100
  alias :include? :has_key?
99
101
 
102
+ # Returns keys of the session as Array.
100
103
  def keys
101
104
  @delegate.keys
102
105
  end
103
106
 
107
+ # Returns values of the session as Array.
104
108
  def values
105
109
  @delegate.values
106
110
  end
107
111
 
112
+ # Writes given value to given key of the session.
108
113
  def []=(key, value)
109
114
  load_for_write!
110
115
  @delegate[key.to_s] = value
111
116
  end
112
117
 
118
+ # Clears the session.
113
119
  def clear
114
120
  load_for_write!
115
121
  @delegate.clear
116
122
  end
117
123
 
124
+ # Returns the session as Hash.
118
125
  def to_hash
119
126
  load_for_read!
120
127
  @delegate.dup.delete_if { |_,v| v.nil? }
121
128
  end
122
129
 
130
+ # Updates the session with given Hash.
131
+ #
132
+ # session.to_hash
133
+ # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2"}
134
+ #
135
+ # session.update({ "foo" => "bar" })
136
+ # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
137
+ #
138
+ # session.to_hash
139
+ # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
123
140
  def update(hash)
124
141
  load_for_write!
125
142
  @delegate.update stringify_keys(hash)
126
143
  end
127
144
 
145
+ # Deletes given key from the session.
128
146
  def delete(key)
129
147
  load_for_write!
130
148
  @delegate.delete key.to_s
131
149
  end
132
150
 
151
+ # Returns value of the given key from the session, or raises +KeyError+
152
+ # if can't find the given key and no default value is set.
153
+ # Returns default value if specified.
154
+ #
155
+ # session.fetch(:foo)
156
+ # # => KeyError: key not found: "foo"
157
+ #
158
+ # session.fetch(:foo, :bar)
159
+ # # => :bar
160
+ #
161
+ # session.fetch(:foo) do
162
+ # :bar
163
+ # end
164
+ # # => :bar
133
165
  def fetch(key, default=Unspecified, &block)
134
166
  load_for_read!
135
167
  if default == Unspecified
@@ -149,7 +181,7 @@ module ActionDispatch
149
181
 
150
182
  def exists?
151
183
  return @exists unless @exists.nil?
152
- @exists = @by.send(:session_exists?, @env)
184
+ @exists = @by.send(:session_exists?, @req)
153
185
  end
154
186
 
155
187
  def loaded?
@@ -166,6 +198,10 @@ module ActionDispatch
166
198
  @delegate.merge!(other)
167
199
  end
168
200
 
201
+ def each(&block)
202
+ to_hash.each(&block)
203
+ end
204
+
169
205
  private
170
206
 
171
207
  def load_for_read!
@@ -177,7 +213,7 @@ module ActionDispatch
177
213
  end
178
214
 
179
215
  def load!
180
- id, session = @by.load_session @env
216
+ id, session = @by.load_session @req
181
217
  options[:id] = id
182
218
  @delegate.replace(stringify_keys(session))
183
219
  @loaded = true
@@ -1,32 +1,64 @@
1
1
  module ActionDispatch
2
- class Request < Rack::Request
2
+ class Request
3
3
  class Utils # :nodoc:
4
4
 
5
5
  mattr_accessor :perform_deep_munge
6
6
  self.perform_deep_munge = true
7
7
 
8
- class << self
9
- # Remove nils from the params hash
10
- def deep_munge(hash, keys = [])
11
- return hash unless perform_deep_munge
8
+ def self.normalize_encode_params(params)
9
+ if perform_deep_munge
10
+ NoNilParamEncoder.normalize_encode_params params
11
+ else
12
+ ParamEncoder.normalize_encode_params params
13
+ end
14
+ end
15
+
16
+ def self.check_param_encoding(params)
17
+ case params
18
+ when Array
19
+ params.each { |element| check_param_encoding(element) }
20
+ when Hash
21
+ params.each_value { |value| check_param_encoding(value) }
22
+ when String
23
+ unless params.valid_encoding?
24
+ # Raise Rack::Utils::InvalidParameterError for consistency with Rack.
25
+ # ActionDispatch::Request#GET will re-raise as a BadRequest error.
26
+ raise Rack::Utils::InvalidParameterError, "Non UTF-8 value: #{params}"
27
+ end
28
+ end
29
+ end
12
30
 
13
- hash.each do |k, v|
14
- keys << k
15
- case v
16
- when Array
17
- v.grep(Hash) { |x| deep_munge(x, keys) }
18
- v.compact!
19
- if v.empty?
20
- hash[k] = nil
21
- ActiveSupport::Notifications.instrument("deep_munge.action_controller", keys: keys)
22
- end
23
- when Hash
24
- deep_munge(v, keys)
31
+ class ParamEncoder # :nodoc:
32
+ # Convert nested Hash to HashWithIndifferentAccess.
33
+ #
34
+ def self.normalize_encode_params(params)
35
+ case params
36
+ when Array
37
+ handle_array params
38
+ when Hash
39
+ if params.has_key?(:tempfile)
40
+ ActionDispatch::Http::UploadedFile.new(params)
41
+ else
42
+ params.each_with_object({}) do |(key, val), new_hash|
43
+ new_hash[key] = normalize_encode_params(val)
44
+ end.with_indifferent_access
25
45
  end
26
- keys.pop
46
+ else
47
+ params
27
48
  end
49
+ end
50
+
51
+ def self.handle_array(params)
52
+ params.map! { |el| normalize_encode_params(el) }
53
+ end
54
+ end
28
55
 
29
- hash
56
+ # Remove nils from the params hash
57
+ class NoNilParamEncoder < ParamEncoder # :nodoc:
58
+ def self.handle_array(params)
59
+ list = super
60
+ list.compact!
61
+ list
30
62
  end
31
63
  end
32
64
  end
@@ -16,10 +16,6 @@ module ActionDispatch
16
16
  app.app
17
17
  end
18
18
 
19
- def verb
20
- super.source.gsub(/[$^]/, '')
21
- end
22
-
23
19
  def path
24
20
  super.spec.to_s
25
21
  end
@@ -28,23 +24,6 @@ module ActionDispatch
28
24
  super.to_s
29
25
  end
30
26
 
31
- def regexp
32
- __getobj__.path.to_regexp
33
- end
34
-
35
- def json_regexp
36
- str = regexp.inspect.
37
- sub('\\A' , '^').
38
- sub('\\Z' , '$').
39
- sub('\\z' , '$').
40
- sub(/^\// , '').
41
- sub(/\/[a-z]*$/ , '').
42
- gsub(/\(\?#.+\)/ , '').
43
- gsub(/\(\?-\w+:/ , '(').
44
- gsub(/\s/ , '')
45
- Regexp.new(str).source
46
- end
47
-
48
27
  def reqs
49
28
  @reqs ||= begin
50
29
  reqs = endpoint
@@ -54,15 +33,15 @@ module ActionDispatch
54
33
  end
55
34
 
56
35
  def controller
57
- requirements[:controller] || ':controller'
36
+ parts.include?(:controller) ? ':controller' : requirements[:controller]
58
37
  end
59
38
 
60
39
  def action
61
- requirements[:action] || ':action'
40
+ parts.include?(:action) ? ':action' : requirements[:action]
62
41
  end
63
42
 
64
43
  def internal?
65
- controller.to_s =~ %r{\Arails/(info|mailers|welcome)} || path =~ %r{\A#{Rails.application.config.assets.prefix}\z}
44
+ internal
66
45
  end
67
46
 
68
47
  def engine?
@@ -72,7 +51,7 @@ module ActionDispatch
72
51
 
73
52
  ##
74
53
  # This class is just used for displaying route information when someone
75
- # executes `rake routes` or looks at the RoutingError page.
54
+ # executes `rails routes` or looks at the RoutingError page.
76
55
  # People should not use this class.
77
56
  class RoutesInspector # :nodoc:
78
57
  def initialize(routes)
@@ -81,12 +60,10 @@ module ActionDispatch
81
60
  end
82
61
 
83
62
  def format(formatter, filter = nil)
84
- routes_to_display = filter_routes(filter)
85
-
63
+ routes_to_display = filter_routes(normalize_filter(filter))
86
64
  routes = collect_routes(routes_to_display)
87
-
88
65
  if routes.none?
89
- formatter.no_routes
66
+ formatter.no_routes(collect_routes(@routes))
90
67
  return formatter.result
91
68
  end
92
69
 
@@ -103,9 +80,20 @@ module ActionDispatch
103
80
 
104
81
  private
105
82
 
83
+ def normalize_filter(filter)
84
+ if filter.is_a?(Hash) && filter[:controller]
85
+ { controller: /#{filter[:controller].downcase.sub(/_?controller\z/, '').sub('::', '/')}/ }
86
+ elsif filter
87
+ { controller: /#{filter}/, action: /#{filter}/, verb: /#{filter}/, name: /#{filter}/, path: /#{filter}/ }
88
+ end
89
+ end
90
+
106
91
  def filter_routes(filter)
107
92
  if filter
108
- @routes.select { |route| route.defaults[:controller] == filter }
93
+ @routes.select do |route|
94
+ route_wrapper = RouteWrapper.new(route)
95
+ filter.any? { |default, value| route_wrapper.send(default) =~ value }
96
+ end
109
97
  else
110
98
  @routes
111
99
  end
@@ -114,16 +102,13 @@ module ActionDispatch
114
102
  def collect_routes(routes)
115
103
  routes.collect do |route|
116
104
  RouteWrapper.new(route)
117
- end.reject do |route|
118
- route.internal?
119
- end.collect do |route|
105
+ end.reject(&:internal?).collect do |route|
120
106
  collect_engine_routes(route)
121
107
 
122
- { name: route.name,
123
- verb: route.verb,
124
- path: route.path,
125
- reqs: route.reqs,
126
- regexp: route.json_regexp }
108
+ { name: route.name,
109
+ verb: route.verb,
110
+ path: route.path,
111
+ reqs: route.reqs }
127
112
  end
128
113
  end
129
114
 
@@ -160,14 +145,18 @@ module ActionDispatch
160
145
  @buffer << draw_header(routes)
161
146
  end
162
147
 
163
- def no_routes
164
- @buffer << <<-MESSAGE.strip_heredoc
148
+ def no_routes(routes)
149
+ @buffer <<
150
+ if routes.none?
151
+ <<-MESSAGE.strip_heredoc
165
152
  You don't have any routes defined!
166
153
 
167
154
  Please add some routes in config/routes.rb.
168
-
169
- For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html.
170
155
  MESSAGE
156
+ else
157
+ "No routes were found for this controller"
158
+ end
159
+ @buffer << "For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html."
171
160
  end
172
161
 
173
162
  private
@@ -211,7 +200,7 @@ module ActionDispatch
211
200
  def header(routes)
212
201
  end
213
202
 
214
- def no_routes
203
+ def no_routes(*)
215
204
  @buffer << <<-MESSAGE.strip_heredoc
216
205
  <p>You don't have any routes defined!</p>
217
206
  <ul>