actionpack 5.2.3
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 +429 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +57 -0
- data/lib/abstract_controller.rb +27 -0
- data/lib/abstract_controller/asset_paths.rb +12 -0
- data/lib/abstract_controller/base.rb +265 -0
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/caching/fragments.rb +166 -0
- data/lib/abstract_controller/callbacks.rb +212 -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 +31 -0
- data/lib/abstract_controller/url_for.rb +35 -0
- data/lib/action_controller.rb +66 -0
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/base.rb +276 -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 +78 -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 +274 -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 +152 -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 +53 -0
- data/lib/action_controller/metal/flash.rb +61 -0
- data/lib/action_controller/metal/force_ssl.rb +99 -0
- data/lib/action_controller/metal/head.rb +60 -0
- data/lib/action_controller/metal/helpers.rb +123 -0
- data/lib/action_controller/metal/http_authentication.rb +519 -0
- data/lib/action_controller/metal/implicit_render.rb +73 -0
- data/lib/action_controller/metal/instrumentation.rb +107 -0
- data/lib/action_controller/metal/live.rb +312 -0
- data/lib/action_controller/metal/mime_responds.rb +313 -0
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +293 -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 +445 -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 +1086 -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 +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +629 -0
- data/lib/action_dispatch.rb +112 -0
- data/lib/action_dispatch/http/cache.rb +222 -0
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +84 -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 +175 -0
- data/lib/action_dispatch/http/mime_type.rb +342 -0
- data/lib/action_dispatch/http/mime_types.rb +50 -0
- data/lib/action_dispatch/http/parameter_filter.rb +86 -0
- data/lib/action_dispatch/http/parameters.rb +126 -0
- data/lib/action_dispatch/http/rack_cache.rb +63 -0
- data/lib/action_dispatch/http/request.rb +430 -0
- data/lib/action_dispatch/http/response.rb +519 -0
- data/lib/action_dispatch/http/upload.rb +84 -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 +49 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
- data/lib/action_dispatch/journey/nodes/node.rb +140 -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 +198 -0
- data/lib/action_dispatch/journey/route.rb +203 -0
- data/lib/action_dispatch/journey/router.rb +156 -0
- data/lib/action_dispatch/journey/router/utils.rb +102 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +64 -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/callbacks.rb +36 -0
- data/lib/action_dispatch/middleware/cookies.rb +685 -0
- data/lib/action_dispatch/middleware/debug_exceptions.rb +205 -0
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +147 -0
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +300 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +57 -0
- data/lib/action_dispatch/middleware/reloader.rb +12 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +183 -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 +118 -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 +116 -0
- data/lib/action_dispatch/middleware/static.rb +130 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -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 +27 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +161 -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 +200 -0
- data/lib/action_dispatch/railtie.rb +55 -0
- data/lib/action_dispatch/request/session.rb +234 -0
- data/lib/action_dispatch/request/utils.rb +78 -0
- data/lib/action_dispatch/routing.rb +260 -0
- data/lib/action_dispatch/routing/endpoint.rb +17 -0
- data/lib/action_dispatch/routing/inspector.rb +225 -0
- data/lib/action_dispatch/routing/mapper.rb +2267 -0
- data/lib/action_dispatch/routing/polymorphic_routes.rb +352 -0
- data/lib/action_dispatch/routing/redirection.rb +201 -0
- data/lib/action_dispatch/routing/route_set.rb +890 -0
- data/lib/action_dispatch/routing/routes_proxy.rb +69 -0
- data/lib/action_dispatch/routing/url_for.rb +236 -0
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -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 +107 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +222 -0
- data/lib/action_dispatch/testing/integration.rb +652 -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 +53 -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 +318 -0
@@ -0,0 +1,212 @@
|
|
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
|
+
##
|
108
|
+
# :method: prepend_before_action
|
109
|
+
#
|
110
|
+
# :call-seq: prepend_before_action(names, block)
|
111
|
+
#
|
112
|
+
# Prepend a callback before actions. See _insert_callbacks for parameter details.
|
113
|
+
|
114
|
+
##
|
115
|
+
# :method: skip_before_action
|
116
|
+
#
|
117
|
+
# :call-seq: skip_before_action(names)
|
118
|
+
#
|
119
|
+
# Skip a callback before actions. See _insert_callbacks for parameter details.
|
120
|
+
|
121
|
+
##
|
122
|
+
# :method: append_before_action
|
123
|
+
#
|
124
|
+
# :call-seq: append_before_action(names, block)
|
125
|
+
#
|
126
|
+
# Append a callback before actions. See _insert_callbacks for parameter details.
|
127
|
+
|
128
|
+
##
|
129
|
+
# :method: after_action
|
130
|
+
#
|
131
|
+
# :call-seq: after_action(names, block)
|
132
|
+
#
|
133
|
+
# Append a callback after actions. See _insert_callbacks for parameter details.
|
134
|
+
|
135
|
+
##
|
136
|
+
# :method: prepend_after_action
|
137
|
+
#
|
138
|
+
# :call-seq: prepend_after_action(names, block)
|
139
|
+
#
|
140
|
+
# Prepend a callback after actions. See _insert_callbacks for parameter details.
|
141
|
+
|
142
|
+
##
|
143
|
+
# :method: skip_after_action
|
144
|
+
#
|
145
|
+
# :call-seq: skip_after_action(names)
|
146
|
+
#
|
147
|
+
# Skip a callback after actions. See _insert_callbacks for parameter details.
|
148
|
+
|
149
|
+
##
|
150
|
+
# :method: append_after_action
|
151
|
+
#
|
152
|
+
# :call-seq: append_after_action(names, block)
|
153
|
+
#
|
154
|
+
# Append a callback after actions. See _insert_callbacks for parameter details.
|
155
|
+
|
156
|
+
##
|
157
|
+
# :method: around_action
|
158
|
+
#
|
159
|
+
# :call-seq: around_action(names, block)
|
160
|
+
#
|
161
|
+
# Append a callback around actions. See _insert_callbacks for parameter details.
|
162
|
+
|
163
|
+
##
|
164
|
+
# :method: prepend_around_action
|
165
|
+
#
|
166
|
+
# :call-seq: prepend_around_action(names, block)
|
167
|
+
#
|
168
|
+
# Prepend a callback around actions. See _insert_callbacks for parameter details.
|
169
|
+
|
170
|
+
##
|
171
|
+
# :method: skip_around_action
|
172
|
+
#
|
173
|
+
# :call-seq: skip_around_action(names)
|
174
|
+
#
|
175
|
+
# Skip a callback around actions. See _insert_callbacks for parameter details.
|
176
|
+
|
177
|
+
##
|
178
|
+
# :method: append_around_action
|
179
|
+
#
|
180
|
+
# :call-seq: append_around_action(names, block)
|
181
|
+
#
|
182
|
+
# Append a callback around actions. See _insert_callbacks for parameter details.
|
183
|
+
|
184
|
+
# set up before_action, prepend_before_action, skip_before_action, etc.
|
185
|
+
# for each of before, after, and around.
|
186
|
+
[:before, :after, :around].each do |callback|
|
187
|
+
define_method "#{callback}_action" do |*names, &blk|
|
188
|
+
_insert_callbacks(names, blk) do |name, options|
|
189
|
+
set_callback(:process_action, callback, name, options)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
define_method "prepend_#{callback}_action" do |*names, &blk|
|
194
|
+
_insert_callbacks(names, blk) do |name, options|
|
195
|
+
set_callback(:process_action, callback, name, options.merge(prepend: true))
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Skip a before, after or around callback. See _insert_callbacks
|
200
|
+
# for details on the allowed parameters.
|
201
|
+
define_method "skip_#{callback}_action" do |*names|
|
202
|
+
_insert_callbacks(names) do |name, options|
|
203
|
+
skip_callback(:process_action, callback, name, options)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# *_action is the same as append_*_action
|
208
|
+
alias_method :"append_#{callback}_action", :"#{callback}_action"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
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
|
+
"http://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
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/dependencies"
|
4
|
+
|
5
|
+
module AbstractController
|
6
|
+
module Helpers
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
class_attribute :_helpers, default: Module.new
|
11
|
+
class_attribute :_helper_methods, default: Array.new
|
12
|
+
end
|
13
|
+
|
14
|
+
class MissingHelperError < LoadError
|
15
|
+
def initialize(error, path)
|
16
|
+
@error = error
|
17
|
+
@path = "helpers/#{path}.rb"
|
18
|
+
set_backtrace error.backtrace
|
19
|
+
|
20
|
+
if error.path =~ /^#{path}(\.rb)?$/
|
21
|
+
super("Missing helper file helpers/%s.rb" % path)
|
22
|
+
else
|
23
|
+
raise error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
# When a class is inherited, wrap its helper module in a new module.
|
30
|
+
# This ensures that the parent class's module can be changed
|
31
|
+
# independently of the child class's.
|
32
|
+
def inherited(klass)
|
33
|
+
helpers = _helpers
|
34
|
+
klass._helpers = Module.new { include helpers }
|
35
|
+
klass.class_eval { default_helper_module! } unless klass.anonymous?
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
# Declare a controller method as a helper. For example, the following
|
40
|
+
# makes the +current_user+ and +logged_in?+ controller methods available
|
41
|
+
# to the view:
|
42
|
+
# class ApplicationController < ActionController::Base
|
43
|
+
# helper_method :current_user, :logged_in?
|
44
|
+
#
|
45
|
+
# def current_user
|
46
|
+
# @current_user ||= User.find_by(id: session[:user])
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# def logged_in?
|
50
|
+
# current_user != nil
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# In a view:
|
55
|
+
# <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
|
56
|
+
#
|
57
|
+
# ==== Parameters
|
58
|
+
# * <tt>method[, method]</tt> - A name or names of a method on the controller
|
59
|
+
# to be made available on the view.
|
60
|
+
def helper_method(*meths)
|
61
|
+
meths.flatten!
|
62
|
+
self._helper_methods += meths
|
63
|
+
|
64
|
+
meths.each do |meth|
|
65
|
+
_helpers.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
|
66
|
+
def #{meth}(*args, &blk) # def current_user(*args, &blk)
|
67
|
+
controller.send(%(#{meth}), *args, &blk) # controller.send(:current_user, *args, &blk)
|
68
|
+
end # end
|
69
|
+
ruby_eval
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# The +helper+ class method can take a series of helper module names, a block, or both.
|
74
|
+
#
|
75
|
+
# ==== Options
|
76
|
+
# * <tt>*args</tt> - Module, Symbol, String
|
77
|
+
# * <tt>block</tt> - A block defining helper methods
|
78
|
+
#
|
79
|
+
# When the argument is a module it will be included directly in the template class.
|
80
|
+
# helper FooHelper # => includes FooHelper
|
81
|
+
#
|
82
|
+
# When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file
|
83
|
+
# and include the module in the template class. The second form illustrates how to include custom helpers
|
84
|
+
# when working with namespaced controllers, or other cases where the file containing the helper definition is not
|
85
|
+
# in one of Rails' standard load paths:
|
86
|
+
# helper :foo # => requires 'foo_helper' and includes FooHelper
|
87
|
+
# helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
|
88
|
+
#
|
89
|
+
# Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
|
90
|
+
# to the template.
|
91
|
+
#
|
92
|
+
# # One line
|
93
|
+
# helper { def hello() "Hello, world!" end }
|
94
|
+
#
|
95
|
+
# # Multi-line
|
96
|
+
# helper do
|
97
|
+
# def foo(bar)
|
98
|
+
# "#{bar} is the very best"
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
|
103
|
+
# +symbols+, +strings+, +modules+ and blocks.
|
104
|
+
#
|
105
|
+
# helper(:three, BlindHelper) { def mice() 'mice' end }
|
106
|
+
#
|
107
|
+
def helper(*args, &block)
|
108
|
+
modules_for_helpers(args).each do |mod|
|
109
|
+
add_template_helper(mod)
|
110
|
+
end
|
111
|
+
|
112
|
+
_helpers.module_eval(&block) if block_given?
|
113
|
+
end
|
114
|
+
|
115
|
+
# Clears up all existing helpers in this class, only keeping the helper
|
116
|
+
# with the same name as this class.
|
117
|
+
def clear_helpers
|
118
|
+
inherited_helper_methods = _helper_methods
|
119
|
+
self._helpers = Module.new
|
120
|
+
self._helper_methods = Array.new
|
121
|
+
|
122
|
+
inherited_helper_methods.each { |meth| helper_method meth }
|
123
|
+
default_helper_module! unless anonymous?
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns a list of modules, normalized from the acceptable kinds of
|
127
|
+
# helpers with the following behavior:
|
128
|
+
#
|
129
|
+
# String or Symbol:: :FooBar or "FooBar" becomes "foo_bar_helper",
|
130
|
+
# and "foo_bar_helper.rb" is loaded using require_dependency.
|
131
|
+
#
|
132
|
+
# Module:: No further processing
|
133
|
+
#
|
134
|
+
# After loading the appropriate files, the corresponding modules
|
135
|
+
# are returned.
|
136
|
+
#
|
137
|
+
# ==== Parameters
|
138
|
+
# * <tt>args</tt> - An array of helpers
|
139
|
+
#
|
140
|
+
# ==== Returns
|
141
|
+
# * <tt>Array</tt> - A normalized list of modules for the list of
|
142
|
+
# helpers provided.
|
143
|
+
def modules_for_helpers(args)
|
144
|
+
args.flatten.map! do |arg|
|
145
|
+
case arg
|
146
|
+
when String, Symbol
|
147
|
+
file_name = "#{arg.to_s.underscore}_helper"
|
148
|
+
begin
|
149
|
+
require_dependency(file_name)
|
150
|
+
rescue LoadError => e
|
151
|
+
raise AbstractController::Helpers::MissingHelperError.new(e, file_name)
|
152
|
+
end
|
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
|
164
|
+
when Module
|
165
|
+
arg
|
166
|
+
else
|
167
|
+
raise ArgumentError, "helper must be a String, Symbol, or Module"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
# Makes all the (instance) methods in the helper module available to templates
|
174
|
+
# rendered through this controller.
|
175
|
+
#
|
176
|
+
# ==== Parameters
|
177
|
+
# * <tt>module</tt> - The module to include into the current helper module
|
178
|
+
# for the class
|
179
|
+
def add_template_helper(mod)
|
180
|
+
_helpers.module_eval { include mod }
|
181
|
+
end
|
182
|
+
|
183
|
+
def default_helper_module!
|
184
|
+
module_name = name.sub(/Controller$/, "".freeze)
|
185
|
+
module_path = module_name.underscore
|
186
|
+
helper module_path
|
187
|
+
rescue LoadError => e
|
188
|
+
raise e unless e.is_missing? "helpers/#{module_path}_helper"
|
189
|
+
rescue NameError => e
|
190
|
+
raise e unless e.missing_name? "#{module_name}Helper"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|