actionpack 6.0.0
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 +7 -0
- data/CHANGELOG.md +311 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +58 -0
- data/lib/abstract_controller.rb +27 -0
- data/lib/abstract_controller/asset_paths.rb +12 -0
- data/lib/abstract_controller/base.rb +267 -0
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/caching/fragments.rb +150 -0
- data/lib/abstract_controller/callbacks.rb +224 -0
- data/lib/abstract_controller/collector.rb +43 -0
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +194 -0
- data/lib/abstract_controller/logger.rb +14 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +20 -0
- data/lib/abstract_controller/rendering.rb +127 -0
- data/lib/abstract_controller/translation.rb +32 -0
- data/lib/abstract_controller/url_for.rb +35 -0
- data/lib/action_controller.rb +67 -0
- data/lib/action_controller/api.rb +150 -0
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/base.rb +271 -0
- data/lib/action_controller/caching.rb +46 -0
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +81 -0
- data/lib/action_controller/metal.rb +256 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +280 -0
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +16 -0
- data/lib/action_controller/metal/data_streaming.rb +151 -0
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
- data/lib/action_controller/metal/exceptions.rb +74 -0
- data/lib/action_controller/metal/flash.rb +61 -0
- data/lib/action_controller/metal/force_ssl.rb +58 -0
- data/lib/action_controller/metal/head.rb +60 -0
- data/lib/action_controller/metal/helpers.rb +122 -0
- data/lib/action_controller/metal/http_authentication.rb +518 -0
- data/lib/action_controller/metal/implicit_render.rb +63 -0
- data/lib/action_controller/metal/instrumentation.rb +105 -0
- data/lib/action_controller/metal/live.rb +314 -0
- data/lib/action_controller/metal/mime_responds.rb +324 -0
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +297 -0
- data/lib/action_controller/metal/redirecting.rb +133 -0
- data/lib/action_controller/metal/renderers.rb +181 -0
- data/lib/action_controller/metal/rendering.rb +122 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +456 -0
- data/lib/action_controller/metal/rescue.rb +28 -0
- data/lib/action_controller/metal/streaming.rb +223 -0
- data/lib/action_controller/metal/strong_parameters.rb +1105 -0
- data/lib/action_controller/metal/testing.rb +16 -0
- data/lib/action_controller/metal/url_for.rb +58 -0
- data/lib/action_controller/railtie.rb +89 -0
- data/lib/action_controller/railties/helpers.rb +24 -0
- data/lib/action_controller/renderer.rb +130 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +626 -0
- data/lib/action_dispatch.rb +114 -0
- data/lib/action_dispatch/http/cache.rb +226 -0
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +284 -0
- data/lib/action_dispatch/http/filter_parameters.rb +86 -0
- data/lib/action_dispatch/http/filter_redirect.rb +37 -0
- data/lib/action_dispatch/http/headers.rb +132 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +177 -0
- data/lib/action_dispatch/http/mime_type.rb +350 -0
- data/lib/action_dispatch/http/mime_types.rb +50 -0
- data/lib/action_dispatch/http/parameter_filter.rb +12 -0
- data/lib/action_dispatch/http/parameters.rb +136 -0
- data/lib/action_dispatch/http/rack_cache.rb +63 -0
- data/lib/action_dispatch/http/request.rb +427 -0
- data/lib/action_dispatch/http/response.rb +534 -0
- data/lib/action_dispatch/http/upload.rb +92 -0
- data/lib/action_dispatch/http/url.rb +350 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/journey/formatter.rb +189 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
- data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
- data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
- data/lib/action_dispatch/journey/nodes/node.rb +141 -0
- data/lib/action_dispatch/journey/parser.rb +199 -0
- data/lib/action_dispatch/journey/parser.y +50 -0
- data/lib/action_dispatch/journey/parser_extras.rb +31 -0
- data/lib/action_dispatch/journey/path/pattern.rb +203 -0
- data/lib/action_dispatch/journey/route.rb +204 -0
- data/lib/action_dispatch/journey/router.rb +153 -0
- data/lib/action_dispatch/journey/router/utils.rb +102 -0
- data/lib/action_dispatch/journey/routes.rb +81 -0
- data/lib/action_dispatch/journey/scanner.rb +71 -0
- data/lib/action_dispatch/journey/visitors.rb +268 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
- data/lib/action_dispatch/middleware/callbacks.rb +34 -0
- data/lib/action_dispatch/middleware/cookies.rb +663 -0
- data/lib/action_dispatch/middleware/debug_exceptions.rb +185 -0
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/debug_view.rb +68 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -0
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +300 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +61 -0
- data/lib/action_dispatch/middleware/reloader.rb +12 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +181 -0
- data/lib/action_dispatch/middleware/request_id.rb +43 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +92 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +54 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +113 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +28 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +62 -0
- data/lib/action_dispatch/middleware/ssl.rb +150 -0
- data/lib/action_dispatch/middleware/stack.rb +148 -0
- data/lib/action_dispatch/middleware/static.rb +129 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +29 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +38 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +165 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +203 -0
- data/lib/action_dispatch/railtie.rb +58 -0
- data/lib/action_dispatch/request/session.rb +242 -0
- data/lib/action_dispatch/request/utils.rb +78 -0
- data/lib/action_dispatch/routing.rb +261 -0
- data/lib/action_dispatch/routing/endpoint.rb +17 -0
- data/lib/action_dispatch/routing/inspector.rb +274 -0
- data/lib/action_dispatch/routing/mapper.rb +2289 -0
- data/lib/action_dispatch/routing/polymorphic_routes.rb +351 -0
- data/lib/action_dispatch/routing/redirection.rb +201 -0
- data/lib/action_dispatch/routing/route_set.rb +887 -0
- data/lib/action_dispatch/routing/routes_proxy.rb +69 -0
- data/lib/action_dispatch/routing/url_for.rb +237 -0
- data/lib/action_dispatch/system_test_case.rb +168 -0
- data/lib/action_dispatch/system_testing/browser.rb +80 -0
- data/lib/action_dispatch/system_testing/driver.rb +68 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +97 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions.rb +24 -0
- data/lib/action_dispatch/testing/assertions/response.rb +106 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +234 -0
- data/lib/action_dispatch/testing/integration.rb +659 -0
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +50 -0
- data/lib/action_dispatch/testing/test_request.rb +71 -0
- data/lib/action_dispatch/testing/test_response.rb +25 -0
- data/lib/action_pack.rb +26 -0
- data/lib/action_pack/gem_version.rb +17 -0
- data/lib/action_pack/version.rb +10 -0
- metadata +329 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbstractController
|
4
|
+
module Caching
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
eager_autoload do
|
9
|
+
autoload :Fragments
|
10
|
+
end
|
11
|
+
|
12
|
+
module ConfigMethods
|
13
|
+
def cache_store
|
14
|
+
config.cache_store
|
15
|
+
end
|
16
|
+
|
17
|
+
def cache_store=(store)
|
18
|
+
config.cache_store = ActiveSupport::Cache.lookup_store(store)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def cache_configured?
|
23
|
+
perform_caching && cache_store
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
include ConfigMethods
|
28
|
+
include AbstractController::Caching::Fragments
|
29
|
+
|
30
|
+
included do
|
31
|
+
extend ConfigMethods
|
32
|
+
|
33
|
+
config_accessor :default_static_extension
|
34
|
+
self.default_static_extension ||= ".html"
|
35
|
+
|
36
|
+
config_accessor :perform_caching
|
37
|
+
self.perform_caching = true if perform_caching.nil?
|
38
|
+
|
39
|
+
config_accessor :enable_fragment_cache_logging
|
40
|
+
self.enable_fragment_cache_logging = false
|
41
|
+
|
42
|
+
class_attribute :_view_cache_dependencies, default: []
|
43
|
+
helper_method :view_cache_dependencies if respond_to?(:helper_method)
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
def view_cache_dependency(&dependency)
|
48
|
+
self._view_cache_dependencies += [dependency]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def view_cache_dependencies
|
53
|
+
self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
# Convenience accessor.
|
58
|
+
def cache(key, options = {}, &block) # :doc:
|
59
|
+
if cache_configured?
|
60
|
+
cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
|
61
|
+
else
|
62
|
+
yield
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbstractController
|
4
|
+
module Caching
|
5
|
+
# Fragment caching is used for caching various blocks within
|
6
|
+
# views without caching the entire action as a whole. This is
|
7
|
+
# useful when certain elements of an action change frequently or
|
8
|
+
# depend on complicated state while other parts rarely change or
|
9
|
+
# can be shared amongst multiple parties. The caching is done using
|
10
|
+
# the +cache+ helper available in the Action View. See
|
11
|
+
# ActionView::Helpers::CacheHelper for more information.
|
12
|
+
#
|
13
|
+
# While it's strongly recommended that you use key-based cache
|
14
|
+
# expiration (see links in CacheHelper for more information),
|
15
|
+
# it is also possible to manually expire caches. For example:
|
16
|
+
#
|
17
|
+
# expire_fragment('name_of_cache')
|
18
|
+
module Fragments
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
included do
|
22
|
+
if respond_to?(:class_attribute)
|
23
|
+
class_attribute :fragment_cache_keys
|
24
|
+
else
|
25
|
+
mattr_writer :fragment_cache_keys
|
26
|
+
end
|
27
|
+
|
28
|
+
self.fragment_cache_keys = []
|
29
|
+
|
30
|
+
if respond_to?(:helper_method)
|
31
|
+
helper_method :combined_fragment_cache_key
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
# Allows you to specify controller-wide key prefixes for
|
37
|
+
# cache fragments. Pass either a constant +value+, or a block
|
38
|
+
# which computes a value each time a cache key is generated.
|
39
|
+
#
|
40
|
+
# For example, you may want to prefix all fragment cache keys
|
41
|
+
# with a global version identifier, so you can easily
|
42
|
+
# invalidate all caches.
|
43
|
+
#
|
44
|
+
# class ApplicationController
|
45
|
+
# fragment_cache_key "v1"
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# When it's time to invalidate all fragments, simply change
|
49
|
+
# the string constant. Or, progressively roll out the cache
|
50
|
+
# invalidation using a computed value:
|
51
|
+
#
|
52
|
+
# class ApplicationController
|
53
|
+
# fragment_cache_key do
|
54
|
+
# @account.id.odd? ? "v1" : "v2"
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
def fragment_cache_key(value = nil, &key)
|
58
|
+
self.fragment_cache_keys += [key || -> { value }]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Given a key (as described in +expire_fragment+), returns
|
63
|
+
# a key array suitable for use in reading, writing, or expiring a
|
64
|
+
# cached fragment. All keys begin with <tt>:views</tt>,
|
65
|
+
# followed by <tt>ENV["RAILS_CACHE_ID"]</tt> or <tt>ENV["RAILS_APP_VERSION"]</tt> if set,
|
66
|
+
# followed by any controller-wide key prefix values, ending
|
67
|
+
# with the specified +key+ value.
|
68
|
+
def combined_fragment_cache_key(key)
|
69
|
+
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
70
|
+
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
71
|
+
|
72
|
+
cache_key = [:views, ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"], head, tail]
|
73
|
+
cache_key.flatten!(1)
|
74
|
+
cache_key.compact!
|
75
|
+
cache_key
|
76
|
+
end
|
77
|
+
|
78
|
+
# Writes +content+ to the location signified by
|
79
|
+
# +key+ (see +expire_fragment+ for acceptable formats).
|
80
|
+
def write_fragment(key, content, options = nil)
|
81
|
+
return content unless cache_configured?
|
82
|
+
|
83
|
+
key = combined_fragment_cache_key(key)
|
84
|
+
instrument_fragment_cache :write_fragment, key do
|
85
|
+
content = content.to_str
|
86
|
+
cache_store.write(key, content, options)
|
87
|
+
end
|
88
|
+
content
|
89
|
+
end
|
90
|
+
|
91
|
+
# Reads a cached fragment from the location signified by +key+
|
92
|
+
# (see +expire_fragment+ for acceptable formats).
|
93
|
+
def read_fragment(key, options = nil)
|
94
|
+
return unless cache_configured?
|
95
|
+
|
96
|
+
key = combined_fragment_cache_key(key)
|
97
|
+
instrument_fragment_cache :read_fragment, key do
|
98
|
+
result = cache_store.read(key, options)
|
99
|
+
result.respond_to?(:html_safe) ? result.html_safe : result
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Check if a cached fragment from the location signified by
|
104
|
+
# +key+ exists (see +expire_fragment+ for acceptable formats).
|
105
|
+
def fragment_exist?(key, options = nil)
|
106
|
+
return unless cache_configured?
|
107
|
+
key = combined_fragment_cache_key(key)
|
108
|
+
|
109
|
+
instrument_fragment_cache :exist_fragment?, key do
|
110
|
+
cache_store.exist?(key, options)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Removes fragments from the cache.
|
115
|
+
#
|
116
|
+
# +key+ can take one of three forms:
|
117
|
+
#
|
118
|
+
# * String - This would normally take the form of a path, like
|
119
|
+
# <tt>pages/45/notes</tt>.
|
120
|
+
# * Hash - Treated as an implicit call to +url_for+, like
|
121
|
+
# <tt>{ controller: 'pages', action: 'notes', id: 45}</tt>
|
122
|
+
# * Regexp - Will remove any fragment that matches, so
|
123
|
+
# <tt>%r{pages/\d*/notes}</tt> might remove all notes. Make sure you
|
124
|
+
# don't use anchors in the regex (<tt>^</tt> or <tt>$</tt>) because
|
125
|
+
# the actual filename matched looks like
|
126
|
+
# <tt>./cache/filename/path.cache</tt>. Note: Regexp expiration is
|
127
|
+
# only supported on caches that can iterate over all keys (unlike
|
128
|
+
# memcached).
|
129
|
+
#
|
130
|
+
# +options+ is passed through to the cache store's +delete+
|
131
|
+
# method (or <tt>delete_matched</tt>, for Regexp keys).
|
132
|
+
def expire_fragment(key, options = nil)
|
133
|
+
return unless cache_configured?
|
134
|
+
key = combined_fragment_cache_key(key) unless key.is_a?(Regexp)
|
135
|
+
|
136
|
+
instrument_fragment_cache :expire_fragment, key do
|
137
|
+
if key.is_a?(Regexp)
|
138
|
+
cache_store.delete_matched(key, options)
|
139
|
+
else
|
140
|
+
cache_store.delete(key, options)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def instrument_fragment_cache(name, key) # :nodoc:
|
146
|
+
ActiveSupport::Notifications.instrument("#{name}.#{instrument_name}", instrument_payload(key)) { yield }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AbstractController
|
4
|
+
# = Abstract Controller Callbacks
|
5
|
+
#
|
6
|
+
# Abstract Controller provides hooks during the life cycle of a controller action.
|
7
|
+
# Callbacks allow you to trigger logic during this cycle. Available callbacks are:
|
8
|
+
#
|
9
|
+
# * <tt>after_action</tt>
|
10
|
+
# * <tt>append_after_action</tt>
|
11
|
+
# * <tt>append_around_action</tt>
|
12
|
+
# * <tt>append_before_action</tt>
|
13
|
+
# * <tt>around_action</tt>
|
14
|
+
# * <tt>before_action</tt>
|
15
|
+
# * <tt>prepend_after_action</tt>
|
16
|
+
# * <tt>prepend_around_action</tt>
|
17
|
+
# * <tt>prepend_before_action</tt>
|
18
|
+
# * <tt>skip_after_action</tt>
|
19
|
+
# * <tt>skip_around_action</tt>
|
20
|
+
# * <tt>skip_before_action</tt>
|
21
|
+
#
|
22
|
+
# NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
|
23
|
+
#
|
24
|
+
module Callbacks
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
|
27
|
+
# Uses ActiveSupport::Callbacks as the base functionality. For
|
28
|
+
# more details on the whole callback system, read the documentation
|
29
|
+
# for ActiveSupport::Callbacks.
|
30
|
+
include ActiveSupport::Callbacks
|
31
|
+
|
32
|
+
included do
|
33
|
+
define_callbacks :process_action,
|
34
|
+
terminator: ->(controller, result_lambda) { result_lambda.call; controller.performed? },
|
35
|
+
skip_after_callbacks_if_terminated: true
|
36
|
+
end
|
37
|
+
|
38
|
+
# Override <tt>AbstractController::Base#process_action</tt> to run the
|
39
|
+
# <tt>process_action</tt> callbacks around the normal behavior.
|
40
|
+
def process_action(*args)
|
41
|
+
run_callbacks(:process_action) do
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
# If +:only+ or +:except+ are used, convert the options into the
|
48
|
+
# +:if+ and +:unless+ options of ActiveSupport::Callbacks.
|
49
|
+
#
|
50
|
+
# The basic idea is that <tt>:only => :index</tt> gets converted to
|
51
|
+
# <tt>:if => proc {|c| c.action_name == "index" }</tt>.
|
52
|
+
#
|
53
|
+
# Note that <tt>:only</tt> has priority over <tt>:if</tt> in case they
|
54
|
+
# are used together.
|
55
|
+
#
|
56
|
+
# only: :index, if: -> { true } # the :if option will be ignored.
|
57
|
+
#
|
58
|
+
# Note that <tt>:if</tt> has priority over <tt>:except</tt> in case they
|
59
|
+
# are used together.
|
60
|
+
#
|
61
|
+
# except: :index, if: -> { true } # the :except option will be ignored.
|
62
|
+
#
|
63
|
+
# ==== Options
|
64
|
+
# * <tt>only</tt> - The callback should be run only for this action.
|
65
|
+
# * <tt>except</tt> - The callback should be run for all actions except this action.
|
66
|
+
def _normalize_callback_options(options)
|
67
|
+
_normalize_callback_option(options, :only, :if)
|
68
|
+
_normalize_callback_option(options, :except, :unless)
|
69
|
+
end
|
70
|
+
|
71
|
+
def _normalize_callback_option(options, from, to) # :nodoc:
|
72
|
+
if from = options[from]
|
73
|
+
_from = Array(from).map(&:to_s).to_set
|
74
|
+
from = proc { |c| _from.include? c.action_name }
|
75
|
+
options[to] = Array(options[to]).unshift(from)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Take callback names and an optional callback proc, normalize them,
|
80
|
+
# then call the block with each callback. This allows us to abstract
|
81
|
+
# the normalization across several methods that use it.
|
82
|
+
#
|
83
|
+
# ==== Parameters
|
84
|
+
# * <tt>callbacks</tt> - An array of callbacks, with an optional
|
85
|
+
# options hash as the last parameter.
|
86
|
+
# * <tt>block</tt> - A proc that should be added to the callbacks.
|
87
|
+
#
|
88
|
+
# ==== Block Parameters
|
89
|
+
# * <tt>name</tt> - The callback to be added.
|
90
|
+
# * <tt>options</tt> - A hash of options to be used when adding the callback.
|
91
|
+
def _insert_callbacks(callbacks, block = nil)
|
92
|
+
options = callbacks.extract_options!
|
93
|
+
_normalize_callback_options(options)
|
94
|
+
callbacks.push(block) if block
|
95
|
+
callbacks.each do |callback|
|
96
|
+
yield callback, options
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# :method: before_action
|
102
|
+
#
|
103
|
+
# :call-seq: before_action(names, block)
|
104
|
+
#
|
105
|
+
# Append a callback before actions. See _insert_callbacks for parameter details.
|
106
|
+
#
|
107
|
+
# If the callback renders or redirects, the action will not run. If there
|
108
|
+
# are additional callbacks scheduled to run after that callback, they are
|
109
|
+
# also cancelled.
|
110
|
+
|
111
|
+
##
|
112
|
+
# :method: prepend_before_action
|
113
|
+
#
|
114
|
+
# :call-seq: prepend_before_action(names, block)
|
115
|
+
#
|
116
|
+
# Prepend a callback before actions. See _insert_callbacks for parameter details.
|
117
|
+
#
|
118
|
+
# If the callback renders or redirects, the action will not run. If there
|
119
|
+
# are additional callbacks scheduled to run after that callback, they are
|
120
|
+
# also cancelled.
|
121
|
+
|
122
|
+
##
|
123
|
+
# :method: skip_before_action
|
124
|
+
#
|
125
|
+
# :call-seq: skip_before_action(names)
|
126
|
+
#
|
127
|
+
# Skip a callback before actions. See _insert_callbacks for parameter details.
|
128
|
+
|
129
|
+
##
|
130
|
+
# :method: append_before_action
|
131
|
+
#
|
132
|
+
# :call-seq: append_before_action(names, block)
|
133
|
+
#
|
134
|
+
# Append a callback before actions. See _insert_callbacks for parameter details.
|
135
|
+
#
|
136
|
+
# If the callback renders or redirects, the action will not run. If there
|
137
|
+
# are additional callbacks scheduled to run after that callback, they are
|
138
|
+
# also cancelled.
|
139
|
+
|
140
|
+
##
|
141
|
+
# :method: after_action
|
142
|
+
#
|
143
|
+
# :call-seq: after_action(names, block)
|
144
|
+
#
|
145
|
+
# Append a callback after actions. See _insert_callbacks for parameter details.
|
146
|
+
|
147
|
+
##
|
148
|
+
# :method: prepend_after_action
|
149
|
+
#
|
150
|
+
# :call-seq: prepend_after_action(names, block)
|
151
|
+
#
|
152
|
+
# Prepend a callback after actions. See _insert_callbacks for parameter details.
|
153
|
+
|
154
|
+
##
|
155
|
+
# :method: skip_after_action
|
156
|
+
#
|
157
|
+
# :call-seq: skip_after_action(names)
|
158
|
+
#
|
159
|
+
# Skip a callback after actions. See _insert_callbacks for parameter details.
|
160
|
+
|
161
|
+
##
|
162
|
+
# :method: append_after_action
|
163
|
+
#
|
164
|
+
# :call-seq: append_after_action(names, block)
|
165
|
+
#
|
166
|
+
# Append a callback after actions. See _insert_callbacks for parameter details.
|
167
|
+
|
168
|
+
##
|
169
|
+
# :method: around_action
|
170
|
+
#
|
171
|
+
# :call-seq: around_action(names, block)
|
172
|
+
#
|
173
|
+
# Append a callback around actions. See _insert_callbacks for parameter details.
|
174
|
+
|
175
|
+
##
|
176
|
+
# :method: prepend_around_action
|
177
|
+
#
|
178
|
+
# :call-seq: prepend_around_action(names, block)
|
179
|
+
#
|
180
|
+
# Prepend a callback around actions. See _insert_callbacks for parameter details.
|
181
|
+
|
182
|
+
##
|
183
|
+
# :method: skip_around_action
|
184
|
+
#
|
185
|
+
# :call-seq: skip_around_action(names)
|
186
|
+
#
|
187
|
+
# Skip a callback around actions. See _insert_callbacks for parameter details.
|
188
|
+
|
189
|
+
##
|
190
|
+
# :method: append_around_action
|
191
|
+
#
|
192
|
+
# :call-seq: append_around_action(names, block)
|
193
|
+
#
|
194
|
+
# Append a callback around actions. See _insert_callbacks for parameter details.
|
195
|
+
|
196
|
+
# set up before_action, prepend_before_action, skip_before_action, etc.
|
197
|
+
# for each of before, after, and around.
|
198
|
+
[:before, :after, :around].each do |callback|
|
199
|
+
define_method "#{callback}_action" do |*names, &blk|
|
200
|
+
_insert_callbacks(names, blk) do |name, options|
|
201
|
+
set_callback(:process_action, callback, name, options)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
define_method "prepend_#{callback}_action" do |*names, &blk|
|
206
|
+
_insert_callbacks(names, blk) do |name, options|
|
207
|
+
set_callback(:process_action, callback, name, options.merge(prepend: true))
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Skip a before, after or around callback. See _insert_callbacks
|
212
|
+
# for details on the allowed parameters.
|
213
|
+
define_method "skip_#{callback}_action" do |*names|
|
214
|
+
_insert_callbacks(names) do |name, options|
|
215
|
+
skip_callback(:process_action, callback, name, options)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# *_action is the same as append_*_action
|
220
|
+
alias_method :"append_#{callback}_action", :"#{callback}_action"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/http/mime_type"
|
4
|
+
|
5
|
+
module AbstractController
|
6
|
+
module Collector
|
7
|
+
def self.generate_method_for_mime(mime)
|
8
|
+
sym = mime.is_a?(Symbol) ? mime : mime.to_sym
|
9
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
10
|
+
def #{sym}(*args, &block)
|
11
|
+
custom(Mime[:#{sym}], *args, &block)
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
|
16
|
+
Mime::SET.each do |mime|
|
17
|
+
generate_method_for_mime(mime)
|
18
|
+
end
|
19
|
+
|
20
|
+
Mime::Type.register_callback do |mime|
|
21
|
+
generate_method_for_mime(mime) unless instance_methods.include?(mime.to_sym)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def method_missing(symbol, &block)
|
27
|
+
unless mime_constant = Mime[symbol]
|
28
|
+
raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
|
29
|
+
"https://guides.rubyonrails.org/action_controller_overview.html#restful-downloads. " \
|
30
|
+
"If you meant to respond to a variant like :tablet or :phone, not a custom format, " \
|
31
|
+
"be sure to nest your variant response within a format response: " \
|
32
|
+
"format.html { |html| html.tablet { ... } }"
|
33
|
+
end
|
34
|
+
|
35
|
+
if Mime::SET.include?(mime_constant)
|
36
|
+
AbstractController::Collector.generate_method_for_mime(mime_constant)
|
37
|
+
send(symbol, &block)
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|