actionpack 4.1.7 → 4.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +311 -527
- data/README.rdoc +7 -2
- data/lib/abstract_controller/base.rb +16 -6
- data/lib/abstract_controller/callbacks.rb +28 -51
- data/lib/abstract_controller/helpers.rb +11 -4
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
- data/lib/abstract_controller/url_for.rb +1 -1
- data/lib/action_controller/base.rb +2 -1
- data/lib/action_controller/caching/fragments.rb +7 -1
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +26 -26
- data/lib/action_controller/metal/conditional_get.rb +37 -12
- data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
- data/lib/action_controller/metal/exceptions.rb +1 -1
- data/lib/action_controller/metal/force_ssl.rb +1 -1
- data/lib/action_controller/metal/head.rb +7 -3
- data/lib/action_controller/metal/http_authentication.rb +14 -9
- data/lib/action_controller/metal/instrumentation.rb +8 -5
- data/lib/action_controller/metal/live.rb +57 -6
- data/lib/action_controller/metal/mime_responds.rb +23 -246
- data/lib/action_controller/metal/params_wrapper.rb +2 -2
- data/lib/action_controller/metal/rack_delegation.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +14 -8
- data/lib/action_controller/metal/renderers.rb +30 -10
- data/lib/action_controller/metal/rendering.rb +2 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +78 -7
- data/lib/action_controller/metal/streaming.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +125 -12
- data/lib/action_controller/metal/url_for.rb +11 -12
- data/lib/action_controller/metal.rb +12 -11
- data/lib/action_controller/model_naming.rb +1 -1
- data/lib/action_controller/railtie.rb +4 -0
- data/lib/action_controller/test_case.rb +112 -75
- data/lib/action_controller.rb +1 -1
- data/lib/action_dispatch/http/cache.rb +5 -4
- data/lib/action_dispatch/http/filter_parameters.rb +2 -2
- data/lib/action_dispatch/http/headers.rb +43 -9
- data/lib/action_dispatch/http/mime_negotiation.rb +10 -3
- data/lib/action_dispatch/http/mime_type.rb +2 -2
- data/lib/action_dispatch/http/parameter_filter.rb +1 -1
- data/lib/action_dispatch/http/parameters.rb +11 -26
- data/lib/action_dispatch/http/request.rb +37 -11
- data/lib/action_dispatch/http/response.rb +70 -18
- data/lib/action_dispatch/http/upload.rb +3 -8
- data/lib/action_dispatch/http/url.rb +88 -69
- data/lib/action_dispatch/journey/formatter.rb +33 -17
- data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +20 -28
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
- data/lib/action_dispatch/journey/nodes/node.rb +4 -0
- data/lib/action_dispatch/journey/parser.rb +52 -60
- data/lib/action_dispatch/journey/parser.y +11 -10
- data/lib/action_dispatch/journey/path/pattern.rb +16 -19
- data/lib/action_dispatch/journey/route.rb +3 -18
- data/lib/action_dispatch/journey/router/strexp.rb +9 -6
- data/lib/action_dispatch/journey/router.rb +53 -77
- data/lib/action_dispatch/journey/scanner.rb +5 -5
- data/lib/action_dispatch/journey/visitors.rb +81 -92
- data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
- data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
- data/lib/action_dispatch/middleware/callbacks.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +29 -29
- data/lib/action_dispatch/middleware/debug_exceptions.rb +15 -4
- data/lib/action_dispatch/middleware/exception_wrapper.rb +50 -18
- data/lib/action_dispatch/middleware/flash.rb +13 -7
- data/lib/action_dispatch/middleware/params_parser.rb +1 -1
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
- data/lib/action_dispatch/middleware/static.rb +66 -37
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +37 -9
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
- data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
- data/lib/action_dispatch/routing/endpoint.rb +10 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -12
- data/lib/action_dispatch/routing/mapper.rb +410 -281
- data/lib/action_dispatch/routing/polymorphic_routes.rb +191 -79
- data/lib/action_dispatch/routing/redirection.rb +10 -12
- data/lib/action_dispatch/routing/route_set.rb +297 -168
- data/lib/action_dispatch/routing/url_for.rb +15 -4
- data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
- data/lib/action_dispatch/testing/assertions/response.rb +2 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
- data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
- data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
- data/lib/action_dispatch/testing/assertions.rb +11 -7
- data/lib/action_dispatch/testing/integration.rb +24 -19
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +7 -0
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +55 -13
- data/lib/action_controller/metal/responder.rb +0 -297
data/README.rdoc
CHANGED
@@ -32,7 +32,7 @@ The latest version of Action Pack can be installed with RubyGems:
|
|
32
32
|
|
33
33
|
Source code can be downloaded as part of the Rails project on GitHub
|
34
34
|
|
35
|
-
* https://github.com/rails/rails/tree/4-
|
35
|
+
* https://github.com/rails/rails/tree/4-2-stable/actionpack
|
36
36
|
|
37
37
|
|
38
38
|
== License
|
@@ -48,6 +48,11 @@ API documentation is at
|
|
48
48
|
|
49
49
|
* http://api.rubyonrails.org
|
50
50
|
|
51
|
-
Bug reports
|
51
|
+
Bug reports can be filed for the Ruby on Rails project here:
|
52
52
|
|
53
53
|
* https://github.com/rails/rails/issues
|
54
|
+
|
55
|
+
Feature requests should be discussed on the rails-core mailing list here:
|
56
|
+
|
57
|
+
* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
|
58
|
+
|
@@ -8,7 +8,8 @@ module AbstractController
|
|
8
8
|
class Error < StandardError #:nodoc:
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
# Raised when a non-existing controller action is triggered.
|
12
|
+
class ActionNotFound < StandardError
|
12
13
|
end
|
13
14
|
|
14
15
|
# <tt>AbstractController::Base</tt> is a low-level API. Nobody should be
|
@@ -120,14 +121,14 @@ module AbstractController
|
|
120
121
|
#
|
121
122
|
# The actual method that is called is determined by calling
|
122
123
|
# #method_for_action. If no method can handle the action, then an
|
123
|
-
# ActionNotFound error is raised.
|
124
|
+
# AbstractController::ActionNotFound error is raised.
|
124
125
|
#
|
125
126
|
# ==== Returns
|
126
127
|
# * <tt>self</tt>
|
127
128
|
def process(action, *args)
|
128
|
-
@_action_name =
|
129
|
+
@_action_name = action.to_s
|
129
130
|
|
130
|
-
unless action_name = _find_action_name(
|
131
|
+
unless action_name = _find_action_name(@_action_name)
|
131
132
|
raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}"
|
132
133
|
end
|
133
134
|
|
@@ -163,6 +164,14 @@ module AbstractController
|
|
163
164
|
_find_action_name(action_name).present?
|
164
165
|
end
|
165
166
|
|
167
|
+
# Returns true if the given controller is capable of rendering
|
168
|
+
# a path. A subclass of +AbstractController::Base+
|
169
|
+
# may return false. An Email controller for example does not
|
170
|
+
# support paths, only full URLs.
|
171
|
+
def self.supports_path?
|
172
|
+
true
|
173
|
+
end
|
174
|
+
|
166
175
|
private
|
167
176
|
|
168
177
|
# Returns true if the name can be considered an action because
|
@@ -215,7 +224,8 @@ module AbstractController
|
|
215
224
|
#
|
216
225
|
# ==== Returns
|
217
226
|
# * <tt>string</tt> - The name of the method that handles the action
|
218
|
-
# * false - No valid method name could be found.
|
227
|
+
# * false - No valid method name could be found.
|
228
|
+
# Raise AbstractController::ActionNotFound.
|
219
229
|
def _find_action_name(action_name)
|
220
230
|
_valid_action_name?(action_name) && method_for_action(action_name)
|
221
231
|
end
|
@@ -235,7 +245,7 @@ module AbstractController
|
|
235
245
|
# the case.
|
236
246
|
#
|
237
247
|
# If none of these conditions are true, and method_for_action
|
238
|
-
# returns nil, an ActionNotFound exception will be raised.
|
248
|
+
# returns nil, an AbstractController::ActionNotFound exception will be raised.
|
239
249
|
#
|
240
250
|
# ==== Parameters
|
241
251
|
# * <tt>action_name</tt> - An action name to find a method name for
|
@@ -42,20 +42,18 @@ module AbstractController
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
# Skip before, after, and around action callbacks matching any of the names
|
46
|
-
# Aliased as skip_filter.
|
45
|
+
# Skip before, after, and around action callbacks matching any of the names.
|
47
46
|
#
|
48
47
|
# ==== Parameters
|
49
48
|
# * <tt>names</tt> - A list of valid names that could be used for
|
50
49
|
# callbacks. Note that skipping uses Ruby equality, so it's
|
51
50
|
# impossible to skip a callback defined using an anonymous proc
|
52
|
-
# using #
|
51
|
+
# using #skip_action_callback
|
53
52
|
def skip_action_callback(*names)
|
54
53
|
skip_before_action(*names)
|
55
54
|
skip_after_action(*names)
|
56
55
|
skip_around_action(*names)
|
57
56
|
end
|
58
|
-
|
59
57
|
alias_method :skip_filter, :skip_action_callback
|
60
58
|
|
61
59
|
# Take callback names and an optional callback proc, normalize them,
|
@@ -85,7 +83,6 @@ module AbstractController
|
|
85
83
|
# :call-seq: before_action(names, block)
|
86
84
|
#
|
87
85
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
88
|
-
# Aliased as before_filter.
|
89
86
|
|
90
87
|
##
|
91
88
|
# :method: prepend_before_action
|
@@ -93,7 +90,6 @@ module AbstractController
|
|
93
90
|
# :call-seq: prepend_before_action(names, block)
|
94
91
|
#
|
95
92
|
# Prepend a callback before actions. See _insert_callbacks for parameter details.
|
96
|
-
# Aliased as prepend_before_filter.
|
97
93
|
|
98
94
|
##
|
99
95
|
# :method: skip_before_action
|
@@ -101,7 +97,6 @@ module AbstractController
|
|
101
97
|
# :call-seq: skip_before_action(names)
|
102
98
|
#
|
103
99
|
# Skip a callback before actions. See _insert_callbacks for parameter details.
|
104
|
-
# Aliased as skip_before_filter.
|
105
100
|
|
106
101
|
##
|
107
102
|
# :method: append_before_action
|
@@ -109,7 +104,6 @@ module AbstractController
|
|
109
104
|
# :call-seq: append_before_action(names, block)
|
110
105
|
#
|
111
106
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
112
|
-
# Aliased as append_before_filter.
|
113
107
|
|
114
108
|
##
|
115
109
|
# :method: after_action
|
@@ -117,7 +111,6 @@ module AbstractController
|
|
117
111
|
# :call-seq: after_action(names, block)
|
118
112
|
#
|
119
113
|
# Append a callback after actions. See _insert_callbacks for parameter details.
|
120
|
-
# Aliased as after_filter.
|
121
114
|
|
122
115
|
##
|
123
116
|
# :method: prepend_after_action
|
@@ -125,7 +118,6 @@ module AbstractController
|
|
125
118
|
# :call-seq: prepend_after_action(names, block)
|
126
119
|
#
|
127
120
|
# Prepend a callback after actions. See _insert_callbacks for parameter details.
|
128
|
-
# Aliased as prepend_after_filter.
|
129
121
|
|
130
122
|
##
|
131
123
|
# :method: skip_after_action
|
@@ -133,7 +125,6 @@ module AbstractController
|
|
133
125
|
# :call-seq: skip_after_action(names)
|
134
126
|
#
|
135
127
|
# Skip a callback after actions. See _insert_callbacks for parameter details.
|
136
|
-
# Aliased as skip_after_filter.
|
137
128
|
|
138
129
|
##
|
139
130
|
# :method: append_after_action
|
@@ -141,7 +132,6 @@ module AbstractController
|
|
141
132
|
# :call-seq: append_after_action(names, block)
|
142
133
|
#
|
143
134
|
# Append a callback after actions. See _insert_callbacks for parameter details.
|
144
|
-
# Aliased as append_after_filter.
|
145
135
|
|
146
136
|
##
|
147
137
|
# :method: around_action
|
@@ -149,7 +139,6 @@ module AbstractController
|
|
149
139
|
# :call-seq: around_action(names, block)
|
150
140
|
#
|
151
141
|
# Append a callback around actions. See _insert_callbacks for parameter details.
|
152
|
-
# Aliased as around_filter.
|
153
142
|
|
154
143
|
##
|
155
144
|
# :method: prepend_around_action
|
@@ -157,7 +146,6 @@ module AbstractController
|
|
157
146
|
# :call-seq: prepend_around_action(names, block)
|
158
147
|
#
|
159
148
|
# Prepend a callback around actions. See _insert_callbacks for parameter details.
|
160
|
-
# Aliased as prepend_around_filter.
|
161
149
|
|
162
150
|
##
|
163
151
|
# :method: skip_around_action
|
@@ -165,7 +153,6 @@ module AbstractController
|
|
165
153
|
# :call-seq: skip_around_action(names)
|
166
154
|
#
|
167
155
|
# Skip a callback around actions. See _insert_callbacks for parameter details.
|
168
|
-
# Aliased as skip_around_filter.
|
169
156
|
|
170
157
|
##
|
171
158
|
# :method: append_around_action
|
@@ -173,46 +160,36 @@ module AbstractController
|
|
173
160
|
# :call-seq: append_around_action(names, block)
|
174
161
|
#
|
175
162
|
# Append a callback around actions. See _insert_callbacks for parameter details.
|
176
|
-
# Aliased as append_around_filter.
|
177
163
|
|
178
164
|
# set up before_action, prepend_before_action, skip_before_action, etc.
|
179
165
|
# for each of before, after, and around.
|
180
166
|
[:before, :after, :around].each do |callback|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
end # end
|
208
|
-
end # end
|
209
|
-
|
210
|
-
alias_method :skip_#{callback}_filter, :skip_#{callback}_action
|
211
|
-
|
212
|
-
# *_action is the same as append_*_action
|
213
|
-
alias_method :append_#{callback}_action, :#{callback}_action # alias_method :append_before_action, :before_action
|
214
|
-
alias_method :append_#{callback}_filter, :#{callback}_action # alias_method :append_before_filter, :before_action
|
215
|
-
RUBY_EVAL
|
167
|
+
define_method "#{callback}_action" do |*names, &blk|
|
168
|
+
_insert_callbacks(names, blk) do |name, options|
|
169
|
+
set_callback(:process_action, callback, name, options)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
alias_method :"#{callback}_filter", :"#{callback}_action"
|
173
|
+
|
174
|
+
define_method "prepend_#{callback}_action" do |*names, &blk|
|
175
|
+
_insert_callbacks(names, blk) do |name, options|
|
176
|
+
set_callback(:process_action, callback, name, options.merge(:prepend => true))
|
177
|
+
end
|
178
|
+
end
|
179
|
+
alias_method :"prepend_#{callback}_filter", :"prepend_#{callback}_action"
|
180
|
+
|
181
|
+
# Skip a before, after or around callback. See _insert_callbacks
|
182
|
+
# for details on the allowed parameters.
|
183
|
+
define_method "skip_#{callback}_action" do |*names|
|
184
|
+
_insert_callbacks(names) do |name, options|
|
185
|
+
skip_callback(:process_action, callback, name, options)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
alias_method :"skip_#{callback}_filter", :"skip_#{callback}_action"
|
189
|
+
|
190
|
+
# *_action is the same as append_*_action
|
191
|
+
alias_method :"append_#{callback}_action", :"#{callback}_action"
|
192
|
+
alias_method :"append_#{callback}_filter", :"#{callback}_action"
|
216
193
|
end
|
217
194
|
end
|
218
195
|
end
|
@@ -27,9 +27,6 @@ module AbstractController
|
|
27
27
|
end
|
28
28
|
|
29
29
|
module ClassMethods
|
30
|
-
MissingHelperError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('AbstractController::Helpers::ClassMethods::MissingHelperError',
|
31
|
-
'AbstractController::Helpers::MissingHelperError')
|
32
|
-
|
33
30
|
# When a class is inherited, wrap its helper module in a new module.
|
34
31
|
# This ensures that the parent class's module can be changed
|
35
32
|
# independently of the child class's.
|
@@ -153,7 +150,17 @@ module AbstractController
|
|
153
150
|
rescue LoadError => e
|
154
151
|
raise AbstractController::Helpers::MissingHelperError.new(e, file_name)
|
155
152
|
end
|
156
|
-
|
153
|
+
|
154
|
+
mod_name = file_name.camelize
|
155
|
+
begin
|
156
|
+
mod_name.constantize
|
157
|
+
rescue LoadError
|
158
|
+
# dependencies.rb gives a similar error message but its wording is
|
159
|
+
# not as clear because it mentions autoloading. To the user all it
|
160
|
+
# matters is that a helper module couldn't be loaded, autoloading
|
161
|
+
# is an internal mechanism that should not leak.
|
162
|
+
raise NameError, "Couldn't find #{mod_name}, expected it to be defined in helpers/#{file_name}.rb"
|
163
|
+
end
|
157
164
|
when Module
|
158
165
|
arg
|
159
166
|
else
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module AbstractController
|
2
2
|
module Railties
|
3
3
|
module RoutesHelpers
|
4
|
-
def self.with(routes)
|
4
|
+
def self.with(routes, include_path_helpers = true)
|
5
5
|
Module.new do
|
6
6
|
define_method(:inherited) do |klass|
|
7
7
|
super(klass)
|
8
8
|
if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
|
9
|
-
klass.send(:include, namespace.railtie_routes_url_helpers)
|
9
|
+
klass.send(:include, namespace.railtie_routes_url_helpers(include_path_helpers))
|
10
10
|
else
|
11
|
-
klass.send(:include, routes.url_helpers)
|
11
|
+
klass.send(:include, routes.url_helpers(include_path_helpers))
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -11,7 +11,7 @@ module AbstractController
|
|
11
11
|
|
12
12
|
def _routes
|
13
13
|
raise "In order to use #url_for, you must include routing helpers explicitly. " \
|
14
|
-
"For instance, `include Rails.application.routes.url_helpers"
|
14
|
+
"For instance, `include Rails.application.routes.url_helpers`."
|
15
15
|
end
|
16
16
|
|
17
17
|
module ClassMethods
|
@@ -44,7 +44,7 @@ module ActionController
|
|
44
44
|
# The full request object is available via the request accessor and is primarily used to query for HTTP headers:
|
45
45
|
#
|
46
46
|
# def server_ip
|
47
|
-
# location = request.env["
|
47
|
+
# location = request.env["REMOTE_ADDR"]
|
48
48
|
# render plain: "This server hosted at #{location}"
|
49
49
|
# end
|
50
50
|
#
|
@@ -213,6 +213,7 @@ module ActionController
|
|
213
213
|
Rendering,
|
214
214
|
Renderers::All,
|
215
215
|
ConditionalGet,
|
216
|
+
EtagWithTemplateDigest,
|
216
217
|
RackDelegation,
|
217
218
|
Caching,
|
218
219
|
MimeResponds,
|
@@ -90,7 +90,13 @@ module ActionController
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def instrument_fragment_cache(name, key) # :nodoc:
|
93
|
-
|
93
|
+
payload = {
|
94
|
+
controller: controller_name,
|
95
|
+
action: action_name,
|
96
|
+
key: key
|
97
|
+
}
|
98
|
+
|
99
|
+
ActiveSupport::Notifications.instrument("#{name}.action_controller", payload) { yield }
|
94
100
|
end
|
95
101
|
end
|
96
102
|
end
|
@@ -16,7 +16,7 @@ module ActionController
|
|
16
16
|
# All the caching stores from ActiveSupport::Cache are available to be used as backends
|
17
17
|
# for Action Controller caching.
|
18
18
|
#
|
19
|
-
# Configuration examples (
|
19
|
+
# Configuration examples (FileStore is the default):
|
20
20
|
#
|
21
21
|
# config.action_controller.cache_store = :memory_store
|
22
22
|
# config.action_controller.cache_store = :file_store, '/path/to/cache/directory'
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ActionController
|
3
2
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
4
3
|
INTERNAL_PARAMS = %w(controller action format _method only_path)
|
@@ -16,50 +15,51 @@ module ActionController
|
|
16
15
|
end
|
17
16
|
|
18
17
|
def process_action(event)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
info do
|
19
|
+
payload = event.payload
|
20
|
+
additions = ActionController::Base.log_process_action(payload)
|
21
|
+
|
22
|
+
status = payload[:status]
|
23
|
+
if status.nil? && payload[:exception].present?
|
24
|
+
exception_class_name = payload[:exception].first
|
25
|
+
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
|
26
|
+
end
|
27
|
+
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
|
28
|
+
message << " (#{additions.join(" | ")})" unless additions.blank?
|
29
|
+
message
|
28
30
|
end
|
29
|
-
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
|
30
|
-
message << " (#{additions.join(" | ")})" unless additions.blank?
|
31
|
-
|
32
|
-
info(message)
|
33
31
|
end
|
34
32
|
|
35
33
|
def halted_callback(event)
|
36
|
-
info
|
34
|
+
info { "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected" }
|
37
35
|
end
|
38
36
|
|
39
37
|
def send_file(event)
|
40
|
-
info
|
38
|
+
info { "Sent file #{event.payload[:path]} (#{event.duration.round(1)}ms)" }
|
41
39
|
end
|
42
40
|
|
43
41
|
def redirect_to(event)
|
44
|
-
info
|
42
|
+
info { "Redirected to #{event.payload[:location]}" }
|
45
43
|
end
|
46
44
|
|
47
45
|
def send_data(event)
|
48
|
-
info
|
46
|
+
info { "Sent data #{event.payload[:filename]} (#{event.duration.round(1)}ms)" }
|
49
47
|
end
|
50
48
|
|
51
49
|
def unpermitted_parameters(event)
|
52
|
-
|
53
|
-
|
50
|
+
debug do
|
51
|
+
unpermitted_keys = event.payload[:keys]
|
52
|
+
"Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.join(", ")}"
|
53
|
+
end
|
54
54
|
end
|
55
55
|
|
56
56
|
def deep_munge(event)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
57
|
+
debug do
|
58
|
+
"Value for params[:#{event.payload[:keys].join('][:')}] was set "\
|
59
|
+
"to nil, because it was one of [], [null] or [null, null, ...]. "\
|
60
|
+
"Go to http://guides.rubyonrails.org/security.html#unsafe-query-generation "\
|
61
|
+
"for more information."\
|
62
|
+
end
|
63
63
|
end
|
64
64
|
|
65
65
|
%w(write_fragment read_fragment exist_fragment?
|
@@ -13,9 +13,9 @@ module ActionController
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module ClassMethods
|
16
|
-
# Allows you to consider additional controller-wide information when generating an
|
16
|
+
# Allows you to consider additional controller-wide information when generating an ETag.
|
17
17
|
# For example, if you serve pages tailored depending on who's logged in at the moment, you
|
18
|
-
# may want to add the current user id to be part of the
|
18
|
+
# may want to add the current user id to be part of the ETag to prevent authorized displaying
|
19
19
|
# of cached pages.
|
20
20
|
#
|
21
21
|
# class InvoicesController < ApplicationController
|
@@ -32,7 +32,7 @@ module ActionController
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
# Sets the etag
|
35
|
+
# Sets the +etag+, +last_modified+, or both on the response and renders a
|
36
36
|
# <tt>304 Not Modified</tt> response if the request is already fresh.
|
37
37
|
#
|
38
38
|
# === Parameters:
|
@@ -41,6 +41,11 @@ module ActionController
|
|
41
41
|
# * <tt>:last_modified</tt>.
|
42
42
|
# * <tt>:public</tt> By default the Cache-Control header is private, set this to
|
43
43
|
# +true+ if you want your application to be cachable by other devices (proxy caches).
|
44
|
+
# * <tt>:template</tt> By default, the template digest for the current
|
45
|
+
# controller/action is included in ETags. If the action renders a
|
46
|
+
# different template, you can include its digest instead. If the action
|
47
|
+
# doesn't render a template at all, you can pass <tt>template: false</tt>
|
48
|
+
# to skip any attempt to check for a template digest.
|
44
49
|
#
|
45
50
|
# === Example:
|
46
51
|
#
|
@@ -49,11 +54,11 @@ module ActionController
|
|
49
54
|
# fresh_when(etag: @article, last_modified: @article.created_at, public: true)
|
50
55
|
# end
|
51
56
|
#
|
52
|
-
# This will render the show template if the request isn't sending a matching
|
57
|
+
# This will render the show template if the request isn't sending a matching ETag or
|
53
58
|
# If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
|
54
59
|
#
|
55
60
|
# You can also just pass a record where +last_modified+ will be set by calling
|
56
|
-
# +updated_at+ and the etag by passing the object itself.
|
61
|
+
# +updated_at+ and the +etag+ by passing the object itself.
|
57
62
|
#
|
58
63
|
# def show
|
59
64
|
# @article = Article.find(params[:id])
|
@@ -66,18 +71,24 @@ module ActionController
|
|
66
71
|
# @article = Article.find(params[:id])
|
67
72
|
# fresh_when(@article, public: true)
|
68
73
|
# end
|
74
|
+
#
|
75
|
+
# When rendering a different template than the default controller/action
|
76
|
+
# style, you can indicate which digest to include in the ETag:
|
77
|
+
#
|
78
|
+
# before_action { fresh_when @article, template: 'widgets/show' }
|
79
|
+
#
|
69
80
|
def fresh_when(record_or_options, additional_options = {})
|
70
81
|
if record_or_options.is_a? Hash
|
71
82
|
options = record_or_options
|
72
|
-
options.assert_valid_keys(:etag, :last_modified, :public)
|
83
|
+
options.assert_valid_keys(:etag, :last_modified, :public, :template)
|
73
84
|
else
|
74
85
|
record = record_or_options
|
75
86
|
options = { etag: record, last_modified: record.try(:updated_at) }.merge!(additional_options)
|
76
87
|
end
|
77
88
|
|
78
|
-
response.etag = combine_etags(options[:etag]
|
79
|
-
response.last_modified = options[:last_modified]
|
80
|
-
response.cache_control[:public] = true
|
89
|
+
response.etag = combine_etags(options) if options[:etag] || options[:template]
|
90
|
+
response.last_modified = options[:last_modified] if options[:last_modified]
|
91
|
+
response.cache_control[:public] = true if options[:public]
|
81
92
|
|
82
93
|
head :not_modified if request.fresh?(response)
|
83
94
|
end
|
@@ -93,6 +104,11 @@ module ActionController
|
|
93
104
|
# * <tt>:last_modified</tt>.
|
94
105
|
# * <tt>:public</tt> By default the Cache-Control header is private, set this to
|
95
106
|
# +true+ if you want your application to be cachable by other devices (proxy caches).
|
107
|
+
# * <tt>:template</tt> By default, the template digest for the current
|
108
|
+
# controller/action is included in ETags. If the action renders a
|
109
|
+
# different template, you can include its digest instead. If the action
|
110
|
+
# doesn't render a template at all, you can pass <tt>template: false</tt>
|
111
|
+
# to skip any attempt to check for a template digest.
|
96
112
|
#
|
97
113
|
# === Example:
|
98
114
|
#
|
@@ -108,7 +124,7 @@ module ActionController
|
|
108
124
|
# end
|
109
125
|
#
|
110
126
|
# You can also just pass a record where +last_modified+ will be set by calling
|
111
|
-
# updated_at and the etag by passing the object itself.
|
127
|
+
# +updated_at+ and the +etag+ by passing the object itself.
|
112
128
|
#
|
113
129
|
# def show
|
114
130
|
# @article = Article.find(params[:id])
|
@@ -133,6 +149,14 @@ module ActionController
|
|
133
149
|
# end
|
134
150
|
# end
|
135
151
|
# end
|
152
|
+
#
|
153
|
+
# When rendering a different template than the default controller/action
|
154
|
+
# style, you can indicate which digest to include in the ETag:
|
155
|
+
#
|
156
|
+
# def show
|
157
|
+
# super if stale? @article, template: 'widgets/show'
|
158
|
+
# end
|
159
|
+
#
|
136
160
|
def stale?(record_or_options, additional_options = {})
|
137
161
|
fresh_when(record_or_options, additional_options)
|
138
162
|
!request.fresh?(response)
|
@@ -168,8 +192,9 @@ module ActionController
|
|
168
192
|
end
|
169
193
|
|
170
194
|
private
|
171
|
-
def combine_etags(
|
172
|
-
|
195
|
+
def combine_etags(options)
|
196
|
+
etags = etaggers.map { |etagger| instance_exec(options, &etagger) }.compact
|
197
|
+
etags.unshift options[:etag]
|
173
198
|
end
|
174
199
|
end
|
175
200
|
end
|