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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +890 -384
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/abstract_controller/base.rb +28 -38
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +51 -11
- data/lib/abstract_controller/caching.rb +62 -0
- data/lib/abstract_controller/callbacks.rb +54 -19
- data/lib/abstract_controller/collector.rb +4 -9
- data/lib/abstract_controller/error.rb +4 -0
- data/lib/abstract_controller/helpers.rb +4 -3
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +28 -18
- data/lib/abstract_controller/translation.rb +8 -7
- data/lib/abstract_controller.rb +6 -2
- data/lib/action_controller/api/api_rendering.rb +14 -0
- data/lib/action_controller/api.rb +147 -0
- data/lib/action_controller/base.rb +14 -11
- data/lib/action_controller/caching.rb +13 -58
- data/lib/action_controller/form_builder.rb +48 -0
- data/lib/action_controller/log_subscriber.rb +3 -10
- data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
- data/lib/action_controller/metal/conditional_get.rb +106 -34
- data/lib/action_controller/metal/cookies.rb +1 -3
- data/lib/action_controller/metal/data_streaming.rb +14 -34
- data/lib/action_controller/metal/etag_with_template_digest.rb +8 -2
- data/lib/action_controller/metal/exceptions.rb +11 -6
- data/lib/action_controller/metal/force_ssl.rb +11 -11
- data/lib/action_controller/metal/head.rb +14 -8
- data/lib/action_controller/metal/helpers.rb +15 -6
- data/lib/action_controller/metal/http_authentication.rb +44 -35
- data/lib/action_controller/metal/implicit_render.rb +61 -6
- data/lib/action_controller/metal/instrumentation.rb +5 -5
- data/lib/action_controller/metal/live.rb +71 -88
- data/lib/action_controller/metal/mime_responds.rb +27 -42
- data/lib/action_controller/metal/params_wrapper.rb +9 -9
- data/lib/action_controller/metal/redirecting.rb +32 -9
- data/lib/action_controller/metal/renderers.rb +83 -40
- data/lib/action_controller/metal/rendering.rb +38 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +126 -48
- data/lib/action_controller/metal/rescue.rb +3 -12
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +527 -134
- data/lib/action_controller/metal/testing.rb +1 -12
- data/lib/action_controller/metal/url_for.rb +12 -5
- data/lib/action_controller/metal.rb +88 -63
- data/lib/action_controller/railtie.rb +11 -7
- data/lib/action_controller/renderer.rb +113 -0
- data/lib/action_controller/template_assertions.rb +9 -0
- data/lib/action_controller/test_case.rb +311 -374
- data/lib/action_controller.rb +12 -9
- data/lib/action_dispatch/http/cache.rb +73 -34
- data/lib/action_dispatch/http/filter_parameters.rb +16 -12
- data/lib/action_dispatch/http/filter_redirect.rb +7 -8
- data/lib/action_dispatch/http/headers.rb +45 -14
- data/lib/action_dispatch/http/mime_negotiation.rb +42 -23
- data/lib/action_dispatch/http/mime_type.rb +126 -90
- data/lib/action_dispatch/http/mime_types.rb +3 -4
- data/lib/action_dispatch/http/parameter_filter.rb +19 -9
- data/lib/action_dispatch/http/parameters.rb +70 -40
- data/lib/action_dispatch/http/request.rb +144 -89
- data/lib/action_dispatch/http/response.rb +215 -102
- data/lib/action_dispatch/http/upload.rb +6 -2
- data/lib/action_dispatch/http/url.rb +117 -8
- data/lib/action_dispatch/journey/formatter.rb +47 -30
- data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
- data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
- data/lib/action_dispatch/journey/nodes/node.rb +14 -4
- data/lib/action_dispatch/journey/parser.rb +2 -0
- data/lib/action_dispatch/journey/parser_extras.rb +8 -2
- data/lib/action_dispatch/journey/path/pattern.rb +38 -42
- data/lib/action_dispatch/journey/route.rb +88 -26
- data/lib/action_dispatch/journey/router/utils.rb +5 -5
- data/lib/action_dispatch/journey/router.rb +8 -10
- data/lib/action_dispatch/journey/routes.rb +14 -15
- data/lib/action_dispatch/journey/visitors.rb +89 -44
- data/lib/action_dispatch/middleware/callbacks.rb +10 -1
- data/lib/action_dispatch/middleware/cookies.rb +188 -134
- data/lib/action_dispatch/middleware/debug_exceptions.rb +128 -49
- data/lib/action_dispatch/middleware/debug_locks.rb +122 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -21
- data/lib/action_dispatch/middleware/executor.rb +19 -0
- data/lib/action_dispatch/middleware/flash.rb +66 -45
- data/lib/action_dispatch/middleware/params_parser.rb +32 -46
- data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +14 -58
- data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
- data/lib/action_dispatch/middleware/request_id.rb +11 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
- data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +30 -24
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
- data/lib/action_dispatch/middleware/ssl.rb +124 -36
- data/lib/action_dispatch/middleware/stack.rb +44 -40
- data/lib/action_dispatch/middleware/static.rb +51 -35
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -63
- data/lib/action_dispatch/railtie.rb +2 -2
- data/lib/action_dispatch/request/session.rb +69 -33
- data/lib/action_dispatch/request/utils.rb +51 -19
- data/lib/action_dispatch/routing/inspector.rb +32 -43
- data/lib/action_dispatch/routing/mapper.rb +515 -348
- data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
- data/lib/action_dispatch/routing/redirection.rb +5 -4
- data/lib/action_dispatch/routing/route_set.rb +148 -240
- data/lib/action_dispatch/routing/url_for.rb +27 -10
- data/lib/action_dispatch/routing.rb +17 -13
- data/lib/action_dispatch/testing/assertion_response.rb +45 -0
- data/lib/action_dispatch/testing/assertions/response.rb +38 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +16 -12
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +377 -149
- data/lib/action_dispatch/testing/request_encoder.rb +53 -0
- data/lib/action_dispatch/testing/test_process.rb +24 -20
- data/lib/action_dispatch/testing/test_request.rb +22 -31
- data/lib/action_dispatch/testing/test_response.rb +12 -4
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +32 -34
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
- /data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
require 'action_controller'
|
3
|
+
require 'action_controller/log_subscriber'
|
4
|
+
|
5
|
+
module ActionController
|
6
|
+
# API Controller is a lightweight version of <tt>ActionController::Base</tt>,
|
7
|
+
# created for applications that don't require all functionalities that a complete
|
8
|
+
# \Rails controller provides, allowing you to create controllers with just the
|
9
|
+
# features that you need for API only applications.
|
10
|
+
#
|
11
|
+
# An API Controller is different from a normal controller in the sense that
|
12
|
+
# by default it doesn't include a number of features that are usually required
|
13
|
+
# by browser access only: layouts and templates rendering, cookies, sessions,
|
14
|
+
# flash, assets, and so on. This makes the entire controller stack thinner,
|
15
|
+
# suitable for API applications. It doesn't mean you won't have such
|
16
|
+
# features if you need them: they're all available for you to include in
|
17
|
+
# your application, they're just not part of the default API controller stack.
|
18
|
+
#
|
19
|
+
# Normally, +ApplicationController+ is the only controller that inherits from
|
20
|
+
# <tt>ActionController::API</tt>. All other controllers in turn inherit from
|
21
|
+
# +ApplicationController+.
|
22
|
+
#
|
23
|
+
# A sample controller could look like this:
|
24
|
+
#
|
25
|
+
# class PostsController < ApplicationController
|
26
|
+
# def index
|
27
|
+
# posts = Post.all
|
28
|
+
# render json: posts
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# Request, response, and parameters objects all work the exact same way as
|
33
|
+
# <tt>ActionController::Base</tt>.
|
34
|
+
#
|
35
|
+
# == Renders
|
36
|
+
#
|
37
|
+
# The default API Controller stack includes all renderers, which means you
|
38
|
+
# can use <tt>render :json</tt> and brothers freely in your controllers. Keep
|
39
|
+
# in mind that templates are not going to be rendered, so you need to ensure
|
40
|
+
# your controller is calling either <tt>render</tt> or <tt>redirect_to</tt> in
|
41
|
+
# all actions, otherwise it will return 204 No Content.
|
42
|
+
#
|
43
|
+
# def show
|
44
|
+
# post = Post.find(params[:id])
|
45
|
+
# render json: post
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# == Redirects
|
49
|
+
#
|
50
|
+
# Redirects are used to move from one action to another. You can use the
|
51
|
+
# <tt>redirect_to</tt> method in your controllers in the same way as in
|
52
|
+
# <tt>ActionController::Base</tt>. For example:
|
53
|
+
#
|
54
|
+
# def create
|
55
|
+
# redirect_to root_url and return if not_authorized?
|
56
|
+
# # do stuff here
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# == Adding New Behavior
|
60
|
+
#
|
61
|
+
# In some scenarios you may want to add back some functionality provided by
|
62
|
+
# <tt>ActionController::Base</tt> that is not present by default in
|
63
|
+
# <tt>ActionController::API</tt>, for instance <tt>MimeResponds</tt>. This
|
64
|
+
# module gives you the <tt>respond_to</tt> method. Adding it is quite simple,
|
65
|
+
# you just need to include the module in a specific controller or in
|
66
|
+
# +ApplicationController+ in case you want it available in your entire
|
67
|
+
# application:
|
68
|
+
#
|
69
|
+
# class ApplicationController < ActionController::API
|
70
|
+
# include ActionController::MimeResponds
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# class PostsController < ApplicationController
|
74
|
+
# def index
|
75
|
+
# posts = Post.all
|
76
|
+
#
|
77
|
+
# respond_to do |format|
|
78
|
+
# format.json { render json: posts }
|
79
|
+
# format.xml { render xml: posts }
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# Quite straightforward. Make sure to check the modules included in
|
85
|
+
# <tt>ActionController::Base</tt> if you want to use any other
|
86
|
+
# functionality that is not provided by <tt>ActionController::API</tt>
|
87
|
+
# out of the box.
|
88
|
+
class API < Metal
|
89
|
+
abstract!
|
90
|
+
|
91
|
+
# Shortcut helper that returns all the ActionController::API modules except
|
92
|
+
# the ones passed as arguments:
|
93
|
+
#
|
94
|
+
# class MyAPIBaseController < ActionController::Metal
|
95
|
+
# ActionController::API.without_modules(:ForceSSL, :UrlFor).each do |left|
|
96
|
+
# include left
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# This gives better control over what you want to exclude and makes it easier
|
101
|
+
# to create an API controller class, instead of listing the modules required
|
102
|
+
# manually.
|
103
|
+
def self.without_modules(*modules)
|
104
|
+
modules = modules.map do |m|
|
105
|
+
m.is_a?(Symbol) ? ActionController.const_get(m) : m
|
106
|
+
end
|
107
|
+
|
108
|
+
MODULES - modules
|
109
|
+
end
|
110
|
+
|
111
|
+
MODULES = [
|
112
|
+
AbstractController::Rendering,
|
113
|
+
|
114
|
+
UrlFor,
|
115
|
+
Redirecting,
|
116
|
+
ApiRendering,
|
117
|
+
Renderers::All,
|
118
|
+
ConditionalGet,
|
119
|
+
BasicImplicitRender,
|
120
|
+
StrongParameters,
|
121
|
+
|
122
|
+
ForceSSL,
|
123
|
+
DataStreaming,
|
124
|
+
|
125
|
+
# Before callbacks should also be executed as early as possible, so
|
126
|
+
# also include them at the bottom.
|
127
|
+
AbstractController::Callbacks,
|
128
|
+
|
129
|
+
# Append rescue at the bottom to wrap as much as possible.
|
130
|
+
Rescue,
|
131
|
+
|
132
|
+
# Add instrumentations hooks at the bottom, to ensure they instrument
|
133
|
+
# all the methods properly.
|
134
|
+
Instrumentation,
|
135
|
+
|
136
|
+
# Params wrapper should come before instrumentation so they are
|
137
|
+
# properly showed in logs
|
138
|
+
ParamsWrapper
|
139
|
+
]
|
140
|
+
|
141
|
+
MODULES.each do |mod|
|
142
|
+
include mod
|
143
|
+
end
|
144
|
+
|
145
|
+
ActiveSupport.run_load_hooks(:action_controller, self)
|
146
|
+
end
|
147
|
+
end
|
@@ -50,9 +50,9 @@ module ActionController
|
|
50
50
|
#
|
51
51
|
# == Parameters
|
52
52
|
#
|
53
|
-
# All request parameters, whether they come from a
|
54
|
-
# which returns a hash. For example, an action that was performed through
|
55
|
-
# <tt>{ "category" => "All", "limit" => "5" }</tt> in params.
|
53
|
+
# All request parameters, whether they come from a query string in the URL or form data submitted through a POST request are
|
54
|
+
# available through the params method which returns a hash. For example, an action that was performed through
|
55
|
+
# <tt>/posts?category=All&limit=5</tt> will include <tt>{ "category" => "All", "limit" => "5" }</tt> in params.
|
56
56
|
#
|
57
57
|
# It's also possible to construct multi-dimensional parameter hashes by specifying keys using brackets, such as:
|
58
58
|
#
|
@@ -206,7 +206,6 @@ module ActionController
|
|
206
206
|
AbstractController::AssetPaths,
|
207
207
|
|
208
208
|
Helpers,
|
209
|
-
HideActions,
|
210
209
|
UrlFor,
|
211
210
|
Redirecting,
|
212
211
|
ActionView::Layouts,
|
@@ -214,7 +213,6 @@ module ActionController
|
|
214
213
|
Renderers::All,
|
215
214
|
ConditionalGet,
|
216
215
|
EtagWithTemplateDigest,
|
217
|
-
RackDelegation,
|
218
216
|
Caching,
|
219
217
|
MimeResponds,
|
220
218
|
ImplicitRender,
|
@@ -222,6 +220,7 @@ module ActionController
|
|
222
220
|
|
223
221
|
Cookies,
|
224
222
|
Flash,
|
223
|
+
FormBuilder,
|
225
224
|
RequestForgeryProtection,
|
226
225
|
ForceSSL,
|
227
226
|
Streaming,
|
@@ -230,7 +229,7 @@ module ActionController
|
|
230
229
|
HttpAuthentication::Digest::ControllerMethods,
|
231
230
|
HttpAuthentication::Token::ControllerMethods,
|
232
231
|
|
233
|
-
# Before callbacks should also be executed
|
232
|
+
# Before callbacks should also be executed as early as possible, so
|
234
233
|
# also include them at the bottom.
|
235
234
|
AbstractController::Callbacks,
|
236
235
|
|
@@ -249,18 +248,22 @@ module ActionController
|
|
249
248
|
MODULES.each do |mod|
|
250
249
|
include mod
|
251
250
|
end
|
251
|
+
setup_renderer!
|
252
252
|
|
253
253
|
# Define some internal variables that should not be propagated to the view.
|
254
|
-
PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES +
|
255
|
-
|
256
|
-
|
254
|
+
PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + %i(
|
255
|
+
@_params @_response @_request @_config @_url_options @_action_has_layout @_view_context_class
|
256
|
+
@_view_renderer @_lookup_context @_routes @_view_runtime @_db_runtime @_helper_proxy
|
257
|
+
)
|
257
258
|
|
258
259
|
def _protected_ivars # :nodoc:
|
259
260
|
PROTECTED_IVARS
|
260
261
|
end
|
261
262
|
|
262
|
-
def self.
|
263
|
-
|
263
|
+
def self.make_response!(request)
|
264
|
+
ActionDispatch::Response.create.tap do |res|
|
265
|
+
res.request = request
|
266
|
+
end
|
264
267
|
end
|
265
268
|
|
266
269
|
ActiveSupport.run_load_hooks(:action_controller, self)
|
@@ -1,14 +1,10 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'uri'
|
3
|
-
require 'set'
|
4
|
-
|
5
1
|
module ActionController
|
6
2
|
# \Caching is a cheap way of speeding up slow applications by keeping the result of
|
7
3
|
# calculations, renderings, and database calls around for subsequent requests.
|
8
4
|
#
|
9
5
|
# You can read more about each approach by clicking the modules below.
|
10
6
|
#
|
11
|
-
# Note: To turn off all caching, set
|
7
|
+
# Note: To turn off all caching provided by Action Controller, set
|
12
8
|
# config.action_controller.perform_caching = false
|
13
9
|
#
|
14
10
|
# == \Caching stores
|
@@ -24,66 +20,25 @@ module ActionController
|
|
24
20
|
# config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211')
|
25
21
|
# config.action_controller.cache_store = MyOwnStore.new('parameter')
|
26
22
|
module Caching
|
27
|
-
extend ActiveSupport::Concern
|
28
23
|
extend ActiveSupport::Autoload
|
29
|
-
|
30
|
-
eager_autoload do
|
31
|
-
autoload :Fragments
|
32
|
-
end
|
33
|
-
|
34
|
-
module ConfigMethods
|
35
|
-
def cache_store
|
36
|
-
config.cache_store
|
37
|
-
end
|
38
|
-
|
39
|
-
def cache_store=(store)
|
40
|
-
config.cache_store = ActiveSupport::Cache.lookup_store(store)
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
def cache_configured?
|
45
|
-
perform_caching && cache_store
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
include RackDelegation
|
50
|
-
include AbstractController::Callbacks
|
51
|
-
|
52
|
-
include ConfigMethods
|
53
|
-
include Fragments
|
24
|
+
extend ActiveSupport::Concern
|
54
25
|
|
55
26
|
included do
|
56
|
-
|
57
|
-
|
58
|
-
config_accessor :default_static_extension
|
59
|
-
self.default_static_extension ||= '.html'
|
60
|
-
|
61
|
-
config_accessor :perform_caching
|
62
|
-
self.perform_caching = true if perform_caching.nil?
|
63
|
-
|
64
|
-
class_attribute :_view_cache_dependencies
|
65
|
-
self._view_cache_dependencies = []
|
66
|
-
helper_method :view_cache_dependencies if respond_to?(:helper_method)
|
27
|
+
include AbstractController::Caching
|
67
28
|
end
|
68
29
|
|
69
|
-
|
70
|
-
def view_cache_dependency(&dependency)
|
71
|
-
self._view_cache_dependencies += [dependency]
|
72
|
-
end
|
73
|
-
end
|
30
|
+
private
|
74
31
|
|
75
|
-
|
76
|
-
|
77
|
-
|
32
|
+
def instrument_payload(key)
|
33
|
+
{
|
34
|
+
controller: controller_name,
|
35
|
+
action: action_name,
|
36
|
+
key: key
|
37
|
+
}
|
38
|
+
end
|
78
39
|
|
79
|
-
|
80
|
-
|
81
|
-
def cache(key, options = {}, &block)
|
82
|
-
if cache_configured?
|
83
|
-
cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
|
84
|
-
else
|
85
|
-
yield
|
86
|
-
end
|
40
|
+
def instrument_name
|
41
|
+
"action_controller"
|
87
42
|
end
|
88
43
|
end
|
89
44
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ActionController
|
2
|
+
# Override the default form builder for all views rendered by this
|
3
|
+
# controller and any of its descendants. Accepts a subclass of
|
4
|
+
# +ActionView::Helpers::FormBuilder+.
|
5
|
+
#
|
6
|
+
# For example, given a form builder:
|
7
|
+
#
|
8
|
+
# class AdminFormBuilder < ActionView::Helpers::FormBuilder
|
9
|
+
# def special_field(name)
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# The controller specifies a form builder as its default:
|
14
|
+
#
|
15
|
+
# class AdminAreaController < ApplicationController
|
16
|
+
# default_form_builder AdminFormBuilder
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Then in the view any form using +form_for+ will be an instance of the
|
20
|
+
# specified form builder:
|
21
|
+
#
|
22
|
+
# <%= form_for(@instance) do |builder| %>
|
23
|
+
# <%= builder.special_field(:name) %>
|
24
|
+
# <% end %>
|
25
|
+
module FormBuilder
|
26
|
+
extend ActiveSupport::Concern
|
27
|
+
|
28
|
+
included do
|
29
|
+
class_attribute :_default_form_builder, instance_accessor: false
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
# Set the form builder to be used as the default for all forms
|
34
|
+
# in the views rendered by this controller and its subclasses.
|
35
|
+
#
|
36
|
+
# ==== Parameters
|
37
|
+
# * <tt>builder</tt> - Default form builder, an instance of +ActionView::Helpers::FormBuilder+
|
38
|
+
def default_form_builder(builder)
|
39
|
+
self._default_form_builder = builder
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Default form builder for the controller
|
44
|
+
def default_form_builder
|
45
|
+
self.class._default_form_builder
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -25,7 +25,9 @@ module ActionController
|
|
25
25
|
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
|
26
26
|
end
|
27
27
|
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
|
28
|
-
message << " (#{additions.join(" | ")})" unless additions.
|
28
|
+
message << " (#{additions.join(" | ".freeze)})" unless additions.empty?
|
29
|
+
message << "\n\n" if defined?(Rails.env) && Rails.env.development?
|
30
|
+
|
29
31
|
message
|
30
32
|
end
|
31
33
|
end
|
@@ -53,15 +55,6 @@ module ActionController
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
def deep_munge(event)
|
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
|
-
end
|
64
|
-
|
65
58
|
%w(write_fragment read_fragment exist_fragment?
|
66
59
|
expire_fragment expire_page write_page).each do |method|
|
67
60
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
@@ -4,7 +4,6 @@ module ActionController
|
|
4
4
|
module ConditionalGet
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
include RackDelegation
|
8
7
|
include Head
|
9
8
|
|
10
9
|
included do
|
@@ -15,7 +14,7 @@ module ActionController
|
|
15
14
|
module ClassMethods
|
16
15
|
# Allows you to consider additional controller-wide information when generating an ETag.
|
17
16
|
# 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 ETag to prevent
|
17
|
+
# may want to add the current user id to be part of the ETag to prevent unauthorized displaying
|
19
18
|
# of cached pages.
|
20
19
|
#
|
21
20
|
# class InvoicesController < ApplicationController
|
@@ -37,10 +36,25 @@ module ActionController
|
|
37
36
|
#
|
38
37
|
# === Parameters:
|
39
38
|
#
|
40
|
-
# * <tt>:etag</tt
|
41
|
-
#
|
39
|
+
# * <tt>:etag</tt> Sets a "weak" ETag validator on the response. See the
|
40
|
+
# +:weak_etag+ option.
|
41
|
+
# * <tt>:weak_etag</tt> Sets a "weak" ETag validator on the response.
|
42
|
+
# Requests that set If-None-Match header may return a 304 Not Modified
|
43
|
+
# response if it matches the ETag exactly. A weak ETag indicates semantic
|
44
|
+
# equivalence, not byte-for-byte equality, so they're good for caching
|
45
|
+
# HTML pages in browser caches. They can't be used for responses that
|
46
|
+
# must be byte-identical, like serving Range requests within a PDF file.
|
47
|
+
# * <tt>:strong_etag</tt> Sets a "strong" ETag validator on the response.
|
48
|
+
# Requests that set If-None-Match header may return a 304 Not Modified
|
49
|
+
# response if it matches the ETag exactly. A strong ETag implies exact
|
50
|
+
# equality: the response must match byte for byte. This is necessary for
|
51
|
+
# doing Range requests within a large video or PDF file, for example, or
|
52
|
+
# for compatibility with some CDNs that don't support weak ETags.
|
53
|
+
# * <tt>:last_modified</tt> Sets a "weak" last-update validator on the
|
54
|
+
# response. Subsequent requests that set If-Modified-Since may return a
|
55
|
+
# 304 Not Modified response if last_modified <= If-Modified-Since.
|
42
56
|
# * <tt>:public</tt> By default the Cache-Control header is private, set this to
|
43
|
-
# +true+ if you want your application to be
|
57
|
+
# +true+ if you want your application to be cacheable by other devices (proxy caches).
|
44
58
|
# * <tt>:template</tt> By default, the template digest for the current
|
45
59
|
# controller/action is included in ETags. If the action renders a
|
46
60
|
# different template, you can include its digest instead. If the action
|
@@ -51,21 +65,31 @@ module ActionController
|
|
51
65
|
#
|
52
66
|
# def show
|
53
67
|
# @article = Article.find(params[:id])
|
54
|
-
# fresh_when(etag: @article, last_modified: @article.
|
68
|
+
# fresh_when(etag: @article, last_modified: @article.updated_at, public: true)
|
55
69
|
# end
|
56
70
|
#
|
57
71
|
# This will render the show template if the request isn't sending a matching ETag or
|
58
72
|
# If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
|
59
73
|
#
|
60
|
-
# You can also just pass a record
|
61
|
-
# +updated_at+ and
|
74
|
+
# You can also just pass a record. In this case +last_modified+ will be set
|
75
|
+
# by calling +updated_at+ and +etag+ by passing the object itself.
|
62
76
|
#
|
63
77
|
# def show
|
64
78
|
# @article = Article.find(params[:id])
|
65
79
|
# fresh_when(@article)
|
66
80
|
# end
|
67
81
|
#
|
68
|
-
#
|
82
|
+
# You can also pass an object that responds to +maximum+, such as a
|
83
|
+
# collection of active records. In this case +last_modified+ will be set by
|
84
|
+
# calling <tt>maximum(:updated_at)</tt> on the collection (the timestamp of the
|
85
|
+
# most recently updated record) and the +etag+ by passing the object itself.
|
86
|
+
#
|
87
|
+
# def index
|
88
|
+
# @articles = Article.all
|
89
|
+
# fresh_when(@articles)
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# When passing a record or a collection, you can still set the public header:
|
69
93
|
#
|
70
94
|
# def show
|
71
95
|
# @article = Article.find(params[:id])
|
@@ -77,18 +101,20 @@ module ActionController
|
|
77
101
|
#
|
78
102
|
# before_action { fresh_when @article, template: 'widgets/show' }
|
79
103
|
#
|
80
|
-
def fresh_when(
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
104
|
+
def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, template: nil)
|
105
|
+
weak_etag ||= etag || object unless strong_etag
|
106
|
+
last_modified ||= object.try(:updated_at) || object.try(:maximum, :updated_at)
|
107
|
+
|
108
|
+
if strong_etag
|
109
|
+
response.strong_etag = combine_etags strong_etag,
|
110
|
+
last_modified: last_modified, public: public, template: template
|
111
|
+
elsif weak_etag || template
|
112
|
+
response.weak_etag = combine_etags weak_etag,
|
113
|
+
last_modified: last_modified, public: public, template: template
|
87
114
|
end
|
88
115
|
|
89
|
-
response.
|
90
|
-
response.
|
91
|
-
response.cache_control[:public] = true if options[:public]
|
116
|
+
response.last_modified = last_modified if last_modified
|
117
|
+
response.cache_control[:public] = true if public
|
92
118
|
|
93
119
|
head :not_modified if request.fresh?(response)
|
94
120
|
end
|
@@ -100,10 +126,25 @@ module ActionController
|
|
100
126
|
#
|
101
127
|
# === Parameters:
|
102
128
|
#
|
103
|
-
# * <tt>:etag</tt
|
104
|
-
#
|
129
|
+
# * <tt>:etag</tt> Sets a "weak" ETag validator on the response. See the
|
130
|
+
# +:weak_etag+ option.
|
131
|
+
# * <tt>:weak_etag</tt> Sets a "weak" ETag validator on the response.
|
132
|
+
# requests that set If-None-Match header may return a 304 Not Modified
|
133
|
+
# response if it matches the ETag exactly. A weak ETag indicates semantic
|
134
|
+
# equivalence, not byte-for-byte equality, so they're good for caching
|
135
|
+
# HTML pages in browser caches. They can't be used for responses that
|
136
|
+
# must be byte-identical, like serving Range requests within a PDF file.
|
137
|
+
# * <tt>:strong_etag</tt> Sets a "strong" ETag validator on the response.
|
138
|
+
# Requests that set If-None-Match header may return a 304 Not Modified
|
139
|
+
# response if it matches the ETag exactly. A strong ETag implies exact
|
140
|
+
# equality: the response must match byte for byte. This is necessary for
|
141
|
+
# doing Range requests within a large video or PDF file, for example, or
|
142
|
+
# for compatibility with some CDNs that don't support weak ETags.
|
143
|
+
# * <tt>:last_modified</tt> Sets a "weak" last-update validator on the
|
144
|
+
# response. Subsequent requests that set If-Modified-Since may return a
|
145
|
+
# 304 Not Modified response if last_modified <= If-Modified-Since.
|
105
146
|
# * <tt>:public</tt> By default the Cache-Control header is private, set this to
|
106
|
-
# +true+ if you want your application to be
|
147
|
+
# +true+ if you want your application to be cacheable by other devices (proxy caches).
|
107
148
|
# * <tt>:template</tt> By default, the template digest for the current
|
108
149
|
# controller/action is included in ETags. If the action renders a
|
109
150
|
# different template, you can include its digest instead. If the action
|
@@ -115,7 +156,7 @@ module ActionController
|
|
115
156
|
# def show
|
116
157
|
# @article = Article.find(params[:id])
|
117
158
|
#
|
118
|
-
# if stale?(etag: @article, last_modified: @article.
|
159
|
+
# if stale?(etag: @article, last_modified: @article.updated_at)
|
119
160
|
# @statistics = @article.really_expensive_call
|
120
161
|
# respond_to do |format|
|
121
162
|
# # all the supported formats
|
@@ -123,8 +164,8 @@ module ActionController
|
|
123
164
|
# end
|
124
165
|
# end
|
125
166
|
#
|
126
|
-
# You can also just pass a record
|
127
|
-
# +updated_at+ and
|
167
|
+
# You can also just pass a record. In this case +last_modified+ will be set
|
168
|
+
# by calling +updated_at+ and +etag+ by passing the object itself.
|
128
169
|
#
|
129
170
|
# def show
|
130
171
|
# @article = Article.find(params[:id])
|
@@ -137,7 +178,23 @@ module ActionController
|
|
137
178
|
# end
|
138
179
|
# end
|
139
180
|
#
|
140
|
-
#
|
181
|
+
# You can also pass an object that responds to +maximum+, such as a
|
182
|
+
# collection of active records. In this case +last_modified+ will be set by
|
183
|
+
# calling +maximum(:updated_at)+ on the collection (the timestamp of the
|
184
|
+
# most recently updated record) and the +etag+ by passing the object itself.
|
185
|
+
#
|
186
|
+
# def index
|
187
|
+
# @articles = Article.all
|
188
|
+
#
|
189
|
+
# if stale?(@articles)
|
190
|
+
# @statistics = @articles.really_expensive_call
|
191
|
+
# respond_to do |format|
|
192
|
+
# # all the supported formats
|
193
|
+
# end
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# When passing a record or a collection, you can still set the public header:
|
141
198
|
#
|
142
199
|
# def show
|
143
200
|
# @article = Article.find(params[:id])
|
@@ -157,12 +214,12 @@ module ActionController
|
|
157
214
|
# super if stale? @article, template: 'widgets/show'
|
158
215
|
# end
|
159
216
|
#
|
160
|
-
def stale?(
|
161
|
-
fresh_when(
|
217
|
+
def stale?(object = nil, **freshness_kwargs)
|
218
|
+
fresh_when(object, **freshness_kwargs)
|
162
219
|
!request.fresh?(response)
|
163
220
|
end
|
164
221
|
|
165
|
-
# Sets
|
222
|
+
# Sets an HTTP 1.1 Cache-Control header. Defaults to issuing a +private+
|
166
223
|
# instruction, so that intermediate caches must not cache the response.
|
167
224
|
#
|
168
225
|
# expires_in 20.minutes
|
@@ -172,7 +229,7 @@ module ActionController
|
|
172
229
|
# This method will overwrite an existing Cache-Control header.
|
173
230
|
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
|
174
231
|
#
|
175
|
-
# The method will also ensure
|
232
|
+
# The method will also ensure an HTTP Date header for client compatibility.
|
176
233
|
def expires_in(seconds, options = {})
|
177
234
|
response.cache_control.merge!(
|
178
235
|
:max_age => seconds,
|
@@ -185,16 +242,31 @@ module ActionController
|
|
185
242
|
response.date = Time.now unless response.date?
|
186
243
|
end
|
187
244
|
|
188
|
-
# Sets
|
245
|
+
# Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should
|
189
246
|
# occur by the browser or intermediate caches (like caching proxy servers).
|
190
247
|
def expires_now
|
191
248
|
response.cache_control.replace(:no_cache => true)
|
192
249
|
end
|
193
250
|
|
251
|
+
# Cache or yield the block. The cache is supposed to never expire.
|
252
|
+
#
|
253
|
+
# You can use this method when you have an HTTP response that never changes,
|
254
|
+
# and the browser and proxies should cache it indefinitely.
|
255
|
+
#
|
256
|
+
# * +public+: By default, HTTP responses are private, cached only on the
|
257
|
+
# user's web browser. To allow proxies to cache the response, set +true+ to
|
258
|
+
# indicate that they can serve the cached response to all users.
|
259
|
+
def http_cache_forever(public: false)
|
260
|
+
expires_in 100.years, public: public
|
261
|
+
|
262
|
+
yield if stale?(etag: request.fullpath,
|
263
|
+
last_modified: Time.new(2011, 1, 1).utc,
|
264
|
+
public: public)
|
265
|
+
end
|
266
|
+
|
194
267
|
private
|
195
|
-
def combine_etags(options)
|
196
|
-
|
197
|
-
etags.unshift options[:etag]
|
268
|
+
def combine_etags(validator, options)
|
269
|
+
[validator, *etaggers.map { |etagger| instance_exec(options, &etagger) }].compact
|
198
270
|
end
|
199
271
|
end
|
200
272
|
end
|