actionview 4.2.11.1 → 7.0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +229 -215
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +116 -43
- data/lib/action_view/buffers.rb +20 -3
- data/lib/action_view/cache_expiry.rb +66 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +21 -122
- data/lib/action_view/digestor.rb +92 -85
- data/lib/action_view/flows.rb +15 -16
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +17 -12
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -101
- data/lib/action_view/helpers/asset_url_helper.rb +180 -74
- data/lib/action_view/helpers/atom_feed_helper.rb +21 -19
- data/lib/action_view/helpers/cache_helper.rb +156 -43
- data/lib/action_view/helpers/capture_helper.rb +21 -14
- data/lib/action_view/helpers/controller_helper.rb +16 -5
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +288 -132
- data/lib/action_view/helpers/debug_helper.rb +9 -6
- data/lib/action_view/helpers/form_helper.rb +956 -173
- data/lib/action_view/helpers/form_options_helper.rb +178 -97
- data/lib/action_view/helpers/form_tag_helper.rb +220 -101
- data/lib/action_view/helpers/javascript_helper.rb +33 -19
- data/lib/action_view/helpers/number_helper.rb +88 -63
- data/lib/action_view/helpers/output_safety_helper.rb +38 -6
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +31 -32
- data/lib/action_view/helpers/tag_helper.rb +332 -71
- data/lib/action_view/helpers/tags/base.rb +123 -99
- data/lib/action_view/helpers/tags/check_box.rb +21 -20
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +5 -3
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +18 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +6 -0
- data/lib/action_view/helpers/tags/label.rb +7 -2
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +12 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +5 -2
- data/lib/action_view/helpers/text_helper.rb +80 -51
- data/lib/action_view/helpers/translation_helper.rb +120 -69
- data/lib/action_view/helpers/url_helper.rb +398 -171
- data/lib/action_view/helpers.rb +29 -27
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +137 -113
- data/lib/action_view/model_naming.rb +4 -2
- data/lib/action_view/path_set.rb +28 -32
- data/lib/action_view/railtie.rb +74 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +152 -15
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +51 -333
- data/lib/action_view/renderer/renderer.rb +68 -11
- data/lib/action_view/renderer/streaming_template_renderer.rb +60 -56
- data/lib/action_view/renderer/template_renderer.rb +87 -74
- data/lib/action_view/rendering.rb +73 -47
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +35 -24
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +151 -41
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +29 -89
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +14 -10
- data/lib/action_view/template/html.rb +12 -13
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +139 -300
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +10 -12
- data/lib/action_view/template/types.rb +28 -26
- data/lib/action_view/template.rb +123 -91
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +70 -53
- data/lib/action_view/testing/resolvers.rb +25 -35
- data/lib/action_view/unbound_template.rb +57 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +16 -11
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +52 -32
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,17 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
# = Action View Cache Helper
|
3
|
-
module Helpers
|
5
|
+
module Helpers # :nodoc:
|
4
6
|
module CacheHelper
|
7
|
+
class UncacheableFragmentError < StandardError; end
|
8
|
+
|
5
9
|
# This helper exposes a method for caching fragments of a view
|
6
10
|
# rather than an entire action or page. This technique is useful
|
7
11
|
# caching pieces like menus, lists of new topics, static HTML
|
8
12
|
# fragments, and so on. This method takes a block that contains
|
9
13
|
# the content you wish to cache.
|
10
14
|
#
|
11
|
-
# The best way to use this is by doing key-based cache expiration
|
12
|
-
# on top of a cache store like Memcached that'll automatically
|
13
|
-
# kick out old entries.
|
14
|
-
# http://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works
|
15
|
+
# The best way to use this is by doing recyclable key-based cache expiration
|
16
|
+
# on top of a cache store like Memcached or Redis that'll automatically
|
17
|
+
# kick out old entries.
|
15
18
|
#
|
16
19
|
# When using this method, you list the cache dependency as the name of the cache, like so:
|
17
20
|
#
|
@@ -23,10 +26,14 @@ module ActionView
|
|
23
26
|
# This approach will assume that when a new topic is added, you'll touch
|
24
27
|
# the project. The cache key generated from this call will be something like:
|
25
28
|
#
|
26
|
-
# views/projects/123
|
27
|
-
# ^
|
29
|
+
# views/template/action:7a1156131a6928cb0026877f8b749ac9/projects/123
|
30
|
+
# ^template path ^template tree digest ^class ^id
|
28
31
|
#
|
29
|
-
#
|
32
|
+
# This cache key is stable, but it's combined with a cache version derived from the project
|
33
|
+
# record. When the project updated_at is touched, the #cache_version changes, even
|
34
|
+
# if the key stays stable. This means that unlike a traditional key-based cache expiration
|
35
|
+
# approach, you won't be generating cache trash, unused keys, simply because the dependent
|
36
|
+
# record is updated.
|
30
37
|
#
|
31
38
|
# If your template cache depends on multiple sources (try to avoid this to keep things simple),
|
32
39
|
# you can name all these dependencies as part of an array:
|
@@ -39,13 +46,13 @@ module ActionView
|
|
39
46
|
# This will include both records as part of the cache key and updating either of them will
|
40
47
|
# expire the cache.
|
41
48
|
#
|
42
|
-
# ==== Template digest
|
49
|
+
# ==== \Template digest
|
43
50
|
#
|
44
|
-
# The template digest that's added to the cache key is computed by taking an
|
51
|
+
# The template digest that's added to the cache key is computed by taking an MD5 of the
|
45
52
|
# contents of the entire template file. This ensures that your caches will automatically
|
46
53
|
# expire when you change the template file.
|
47
54
|
#
|
48
|
-
# Note that the
|
55
|
+
# Note that the MD5 is taken of the entire template file, not just what's within the
|
49
56
|
# cache do/end call. So it's possible that changing something outside of that call will
|
50
57
|
# still expire the cache.
|
51
58
|
#
|
@@ -69,13 +76,14 @@ module ActionView
|
|
69
76
|
# render 'comments/comments'
|
70
77
|
# render('comments/comments')
|
71
78
|
#
|
72
|
-
# render "header"
|
79
|
+
# render "header" translates to render("comments/header")
|
73
80
|
#
|
74
|
-
# render(@topic)
|
75
|
-
# render(topics)
|
76
|
-
# render(message.topics)
|
81
|
+
# render(@topic) translates to render("topics/topic")
|
82
|
+
# render(topics) translates to render("topics/topic")
|
83
|
+
# render(message.topics) translates to render("topics/topic")
|
77
84
|
#
|
78
|
-
# It's not possible to derive all render calls like that, though.
|
85
|
+
# It's not possible to derive all render calls like that, though.
|
86
|
+
# Here are a few examples of things that can't be derived:
|
79
87
|
#
|
80
88
|
# render group_of_attachments
|
81
89
|
# render @project.documents.where(published: true).order('created_at')
|
@@ -87,7 +95,7 @@ module ActionView
|
|
87
95
|
#
|
88
96
|
# === Explicit dependencies
|
89
97
|
#
|
90
|
-
#
|
98
|
+
# Sometimes you'll have template dependencies that can't be derived at all. This is typically
|
91
99
|
# the case when you have template rendering that happens in helpers. Here's an example:
|
92
100
|
#
|
93
101
|
# <%= render_sortable_todolists @project.todolists %>
|
@@ -97,22 +105,72 @@ module ActionView
|
|
97
105
|
# <%# Template Dependency: todolists/todolist %>
|
98
106
|
# <%= render_sortable_todolists @project.todolists %>
|
99
107
|
#
|
100
|
-
#
|
108
|
+
# In some cases, like a single table inheritance setup, you might have
|
109
|
+
# a bunch of explicit dependencies. Instead of writing every template out,
|
110
|
+
# you can use a wildcard to match any template in a directory:
|
111
|
+
#
|
112
|
+
# <%# Template Dependency: events/* %>
|
113
|
+
# <%= render_categorizable_events @person.events %>
|
114
|
+
#
|
115
|
+
# This marks every template in the directory as a dependency. To find those
|
116
|
+
# templates, the wildcard path must be absolutely defined from <tt>app/views</tt> or paths
|
117
|
+
# otherwise added with +prepend_view_path+ or +append_view_path+.
|
118
|
+
# This way the wildcard for <tt>app/views/recordings/events</tt> would be <tt>recordings/events/*</tt> etc.
|
119
|
+
#
|
120
|
+
# The pattern used to match explicit dependencies is <tt>/# Template Dependency: (\S+)/</tt>,
|
121
|
+
# so it's important that you type it out just so.
|
101
122
|
# You can only declare one template dependency per line.
|
102
123
|
#
|
103
124
|
# === External dependencies
|
104
125
|
#
|
105
|
-
# If you use a helper method, for example, inside
|
106
|
-
# you'll have to bump the cache as well.
|
126
|
+
# If you use a helper method, for example, inside a cached block and
|
127
|
+
# you then update that helper, you'll have to bump the cache as well.
|
128
|
+
# It doesn't really matter how you do it, but the MD5 of the template file
|
107
129
|
# must change. One recommendation is to simply be explicit in a comment, like:
|
108
130
|
#
|
109
131
|
# <%# Helper Dependency Updated: May 6, 2012 at 6pm %>
|
110
132
|
# <%= some_helper_method(person) %>
|
111
133
|
#
|
112
|
-
# Now all you
|
113
|
-
|
134
|
+
# Now all you have to do is change that timestamp when the helper method changes.
|
135
|
+
#
|
136
|
+
# === Collection Caching
|
137
|
+
#
|
138
|
+
# When rendering a collection of objects that each use the same partial, a <tt>:cached</tt>
|
139
|
+
# option can be passed.
|
140
|
+
#
|
141
|
+
# For collections rendered such:
|
142
|
+
#
|
143
|
+
# <%= render partial: 'projects/project', collection: @projects, cached: true %>
|
144
|
+
#
|
145
|
+
# The <tt>cached: true</tt> will make Action View's rendering read several templates
|
146
|
+
# from cache at once instead of one call per template.
|
147
|
+
#
|
148
|
+
# Templates in the collection not already cached are written to cache.
|
149
|
+
#
|
150
|
+
# Works great alongside individual template fragment caching.
|
151
|
+
# For instance if the template the collection renders is cached like:
|
152
|
+
#
|
153
|
+
# # projects/_project.html.erb
|
154
|
+
# <% cache project do %>
|
155
|
+
# <%# ... %>
|
156
|
+
# <% end %>
|
157
|
+
#
|
158
|
+
# Any collection renders will find those cached templates when attempting
|
159
|
+
# to read multiple templates at once.
|
160
|
+
#
|
161
|
+
# If your collection cache depends on multiple sources (try to avoid this to keep things simple),
|
162
|
+
# you can name all these dependencies as part of a block that returns an array:
|
163
|
+
#
|
164
|
+
# <%= render partial: 'projects/project', collection: @projects, cached: -> project { [ project, current_user ] } %>
|
165
|
+
#
|
166
|
+
# This will include both records as part of the cache key and updating either of them will
|
167
|
+
# expire the cache.
|
168
|
+
def cache(name = {}, options = {}, &block)
|
114
169
|
if controller.respond_to?(:perform_caching) && controller.perform_caching
|
115
|
-
|
170
|
+
CachingRegistry.track_caching do
|
171
|
+
name_options = options.slice(:skip_digest)
|
172
|
+
safe_concat(fragment_for(cache_fragment_name(name, **name_options), options, &block))
|
173
|
+
end
|
116
174
|
else
|
117
175
|
yield
|
118
176
|
end
|
@@ -120,13 +178,41 @@ module ActionView
|
|
120
178
|
nil
|
121
179
|
end
|
122
180
|
|
181
|
+
# Returns whether the current view fragment is within a +cache+ block.
|
182
|
+
#
|
183
|
+
# Useful when certain fragments aren't cacheable:
|
184
|
+
#
|
185
|
+
# <% cache project do %>
|
186
|
+
# <% raise StandardError, "Caching private data!" if caching? %>
|
187
|
+
# <% end %>
|
188
|
+
def caching?
|
189
|
+
CachingRegistry.caching?
|
190
|
+
end
|
191
|
+
|
192
|
+
# Raises +UncacheableFragmentError+ when called from within a +cache+ block.
|
193
|
+
#
|
194
|
+
# Useful to denote helper methods that can't participate in fragment caching:
|
195
|
+
#
|
196
|
+
# def project_name_with_time(project)
|
197
|
+
# uncacheable!
|
198
|
+
# "#{project.name} - #{Time.now}"
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# # Which will then raise if used within a +cache+ block:
|
202
|
+
# <% cache project do %>
|
203
|
+
# <%= project_name_with_time(project) %>
|
204
|
+
# <% end %>
|
205
|
+
def uncacheable!
|
206
|
+
raise UncacheableFragmentError, "can't be fragment cached" if caching?
|
207
|
+
end
|
208
|
+
|
123
209
|
# Cache fragments of a view if +condition+ is true
|
124
210
|
#
|
125
211
|
# <% cache_if admin?, project do %>
|
126
212
|
# <b>All the topics on this project</b>
|
127
213
|
# <%= render project.topics %>
|
128
214
|
# <% end %>
|
129
|
-
def cache_if(condition, name = {}, options =
|
215
|
+
def cache_if(condition, name = {}, options = {}, &block)
|
130
216
|
if condition
|
131
217
|
cache(name, options, &block)
|
132
218
|
else
|
@@ -142,50 +228,60 @@ module ActionView
|
|
142
228
|
# <b>All the topics on this project</b>
|
143
229
|
# <%= render project.topics %>
|
144
230
|
# <% end %>
|
145
|
-
def cache_unless(condition, name = {}, options =
|
231
|
+
def cache_unless(condition, name = {}, options = {}, &block)
|
146
232
|
cache_if !condition, name, options, &block
|
147
233
|
end
|
148
234
|
|
149
235
|
# This helper returns the name of a cache key for a given fragment cache
|
150
|
-
# call. By supplying skip_digest: true to cache, the digestion of cache
|
236
|
+
# call. By supplying <tt>skip_digest: true</tt> to cache, the digestion of cache
|
151
237
|
# fragments can be manually bypassed. This is useful when cache fragments
|
152
238
|
# cannot be manually expired unless you know the exact key which is the
|
153
239
|
# case when using memcached.
|
154
|
-
def cache_fragment_name(name = {},
|
155
|
-
skip_digest = options && options[:skip_digest]
|
156
|
-
|
240
|
+
def cache_fragment_name(name = {}, skip_digest: nil, digest_path: nil)
|
157
241
|
if skip_digest
|
158
242
|
name
|
159
243
|
else
|
160
|
-
fragment_name_with_digest(name)
|
244
|
+
fragment_name_with_digest(name, digest_path)
|
161
245
|
end
|
162
246
|
end
|
163
247
|
|
164
|
-
|
248
|
+
def digest_path_from_template(template) # :nodoc:
|
249
|
+
digest = Digestor.digest(name: template.virtual_path, format: template.format, finder: lookup_context, dependencies: view_cache_dependencies)
|
165
250
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
251
|
+
if digest.present?
|
252
|
+
"#{template.virtual_path}:#{digest}"
|
253
|
+
else
|
254
|
+
template.virtual_path
|
255
|
+
end
|
256
|
+
end
|
170
257
|
|
171
|
-
|
258
|
+
private
|
259
|
+
def fragment_name_with_digest(name, digest_path)
|
260
|
+
name = controller.url_for(name).split("://").last if name.is_a?(Hash)
|
261
|
+
|
262
|
+
if @current_template&.virtual_path || digest_path
|
263
|
+
digest_path ||= digest_path_from_template(@current_template)
|
264
|
+
[ digest_path, name ]
|
172
265
|
else
|
173
266
|
name
|
174
267
|
end
|
175
268
|
end
|
176
269
|
|
177
|
-
|
178
|
-
|
179
|
-
|
270
|
+
def fragment_for(name = {}, options = nil, &block)
|
271
|
+
if content = read_fragment_for(name, options)
|
272
|
+
@view_renderer.cache_hits[@current_template&.virtual_path] = :hit if defined?(@view_renderer)
|
273
|
+
content
|
274
|
+
else
|
275
|
+
@view_renderer.cache_hits[@current_template&.virtual_path] = :miss if defined?(@view_renderer)
|
276
|
+
write_fragment_for(name, options, &block)
|
277
|
+
end
|
180
278
|
end
|
181
279
|
|
182
|
-
def read_fragment_for(name, options)
|
280
|
+
def read_fragment_for(name, options)
|
183
281
|
controller.read_fragment(name, options)
|
184
282
|
end
|
185
283
|
|
186
|
-
def write_fragment_for(name, options)
|
187
|
-
# VIEW TODO: Make #capture usable outside of ERB
|
188
|
-
# This dance is needed because Builder can't use capture
|
284
|
+
def write_fragment_for(name, options)
|
189
285
|
pos = output_buffer.length
|
190
286
|
yield
|
191
287
|
output_safe = output_buffer.html_safe?
|
@@ -195,6 +291,23 @@ module ActionView
|
|
195
291
|
end
|
196
292
|
controller.write_fragment(name, fragment, options)
|
197
293
|
end
|
294
|
+
|
295
|
+
module CachingRegistry # :nodoc:
|
296
|
+
extend self
|
297
|
+
|
298
|
+
def caching?
|
299
|
+
ActiveSupport::IsolatedExecutionState[:action_view_caching] ||= false
|
300
|
+
end
|
301
|
+
|
302
|
+
def track_caching
|
303
|
+
caching_was = ActiveSupport::IsolatedExecutionState[:action_view_caching]
|
304
|
+
ActiveSupport::IsolatedExecutionState[:action_view_caching] = true
|
305
|
+
|
306
|
+
yield
|
307
|
+
ensure
|
308
|
+
ActiveSupport::IsolatedExecutionState[:action_view_caching] = caching_was
|
309
|
+
end
|
310
|
+
end
|
198
311
|
end
|
199
312
|
end
|
200
313
|
end
|
@@ -1,16 +1,18 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/output_safety"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
# = Action View Capture Helper
|
5
|
-
module Helpers
|
7
|
+
module Helpers # :nodoc:
|
6
8
|
# CaptureHelper exposes methods to let you extract generated markup which
|
7
9
|
# can be used in other parts of a template or layout file.
|
8
10
|
#
|
9
11
|
# It provides a method to capture blocks into variables through capture and
|
10
|
-
# a way to capture a block of markup for use in a layout through content_for.
|
12
|
+
# a way to capture a block of markup for use in a layout through {content_for}[rdoc-ref:ActionView::Helpers::CaptureHelper#content_for].
|
11
13
|
module CaptureHelper
|
12
|
-
# The capture method
|
13
|
-
#
|
14
|
+
# The capture method extracts part of a template as a String object.
|
15
|
+
# You can then use this object anywhere in your templates, layout, or helpers.
|
14
16
|
#
|
15
17
|
# The capture method can be used in ERB templates...
|
16
18
|
#
|
@@ -31,17 +33,22 @@ module ActionView
|
|
31
33
|
# <head><title><%= @greeting %></title></head>
|
32
34
|
# <body>
|
33
35
|
# <b><%= @greeting %></b>
|
34
|
-
# </body
|
36
|
+
# </body>
|
37
|
+
# </html>
|
38
|
+
#
|
39
|
+
# The return of capture is the string generated by the block. For Example:
|
40
|
+
#
|
41
|
+
# @greeting # => "Welcome to my shiny new web page! The date and time is 2018-09-06 11:09:16 -0500"
|
35
42
|
#
|
36
43
|
def capture(*args)
|
37
44
|
value = nil
|
38
45
|
buffer = with_output_buffer { value = yield(*args) }
|
39
|
-
if string = buffer.presence || value
|
46
|
+
if (string = buffer.presence || value) && string.is_a?(String)
|
40
47
|
ERB::Util.html_escape string
|
41
48
|
end
|
42
49
|
end
|
43
50
|
|
44
|
-
# Calling content_for stores a block of markup in an identifier for later use.
|
51
|
+
# Calling <tt>content_for</tt> stores a block of markup in an identifier for later use.
|
45
52
|
# In order to access this stored content in other templates, helper modules
|
46
53
|
# or the layout, you would pass the identifier as an argument to <tt>content_for</tt>.
|
47
54
|
#
|
@@ -107,14 +114,14 @@ module ActionView
|
|
107
114
|
# That will place +script+ tags for your default set of JavaScript files on the page;
|
108
115
|
# this technique is useful if you'll only be using these scripts in a few views.
|
109
116
|
#
|
110
|
-
# Note that content_for concatenates (default) the blocks it is given for a particular
|
117
|
+
# Note that <tt>content_for</tt> concatenates (default) the blocks it is given for a particular
|
111
118
|
# identifier in order. For example:
|
112
119
|
#
|
113
120
|
# <% content_for :navigation do %>
|
114
121
|
# <li><%= link_to 'Home', action: 'index' %></li>
|
115
122
|
# <% end %>
|
116
123
|
#
|
117
|
-
# And in
|
124
|
+
# And in another place:
|
118
125
|
#
|
119
126
|
# <% content_for :navigation do %>
|
120
127
|
# <li><%= link_to 'Login', action: 'login' %></li>
|
@@ -124,7 +131,7 @@ module ActionView
|
|
124
131
|
#
|
125
132
|
# <ul><%= content_for :navigation %></ul>
|
126
133
|
#
|
127
|
-
# If the flush parameter is true content_for replaces the blocks it is given. For example:
|
134
|
+
# If the flush parameter is +true+ <tt>content_for</tt> replaces the blocks it is given. For example:
|
128
135
|
#
|
129
136
|
# <% content_for :navigation do %>
|
130
137
|
# <li><%= link_to 'Home', action: 'index' %></li>
|
@@ -144,7 +151,7 @@ module ActionView
|
|
144
151
|
#
|
145
152
|
# <% content_for :script, javascript_include_tag(:defaults) %>
|
146
153
|
#
|
147
|
-
# WARNING: content_for is ignored in caches. So you shouldn't use it for elements that will be fragment cached.
|
154
|
+
# WARNING: <tt>content_for</tt> is ignored in caches. So you shouldn't use it for elements that will be fragment cached.
|
148
155
|
def content_for(name, content = nil, options = {}, &block)
|
149
156
|
if content || block_given?
|
150
157
|
if block_given?
|
@@ -171,7 +178,7 @@ module ActionView
|
|
171
178
|
result unless content
|
172
179
|
end
|
173
180
|
|
174
|
-
# content_for
|
181
|
+
# <tt>content_for?</tt> checks whether any content has been captured yet using <tt>content_for</tt>.
|
175
182
|
# Useful to render parts of your layout differently based on what is in your views.
|
176
183
|
#
|
177
184
|
# <%# This is the layout %>
|
@@ -191,7 +198,7 @@ module ActionView
|
|
191
198
|
|
192
199
|
# Use an alternate output buffer for the duration of the block.
|
193
200
|
# Defaults to a new empty string.
|
194
|
-
def with_output_buffer(buf = nil)
|
201
|
+
def with_output_buffer(buf = nil) # :nodoc:
|
195
202
|
unless buf
|
196
203
|
buf = ActionView::OutputBuffer.new
|
197
204
|
if output_buffer && output_buffer.respond_to?(:encoding)
|
@@ -1,25 +1,36 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attr_internal"
|
2
4
|
|
3
5
|
module ActionView
|
4
|
-
module Helpers
|
6
|
+
module Helpers # :nodoc:
|
5
7
|
# This module keeps all methods and behavior in ActionView
|
6
8
|
# that simply delegates to the controller.
|
7
|
-
module ControllerHelper
|
9
|
+
module ControllerHelper # :nodoc:
|
8
10
|
attr_internal :controller, :request
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
CONTROLLER_DELEGATES = [:request_forgery_protection_token, :params,
|
13
|
+
:session, :cookies, :response, :headers, :flash, :action_name,
|
14
|
+
:controller_name, :controller_path]
|
15
|
+
|
16
|
+
delegate(*CONTROLLER_DELEGATES, to: :controller)
|
12
17
|
|
13
18
|
def assign_controller(controller)
|
14
19
|
if @_controller = controller
|
15
20
|
@_request = controller.request if controller.respond_to?(:request)
|
16
21
|
@_config = controller.config.inheritable_copy if controller.respond_to?(:config)
|
22
|
+
@_default_form_builder = controller.default_form_builder if controller.respond_to?(:default_form_builder)
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
20
26
|
def logger
|
21
27
|
controller.logger if controller.respond_to?(:logger)
|
22
28
|
end
|
29
|
+
|
30
|
+
def respond_to?(method_name, include_private = false)
|
31
|
+
return controller.respond_to?(method_name) if CONTROLLER_DELEGATES.include?(method_name.to_sym)
|
32
|
+
super
|
33
|
+
end
|
23
34
|
end
|
24
35
|
end
|
25
36
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
# = Action View CSP Helper
|
5
|
+
module Helpers # :nodoc:
|
6
|
+
module CspHelper
|
7
|
+
# Returns a meta tag "csp-nonce" with the per-session nonce value
|
8
|
+
# for allowing inline <script> tags.
|
9
|
+
#
|
10
|
+
# <head>
|
11
|
+
# <%= csp_meta_tag %>
|
12
|
+
# </head>
|
13
|
+
#
|
14
|
+
# This is used by the Rails UJS helper to create dynamically
|
15
|
+
# loaded inline <script> elements.
|
16
|
+
#
|
17
|
+
def csp_meta_tag(**options)
|
18
|
+
if content_security_policy?
|
19
|
+
options[:name] = "csp-nonce"
|
20
|
+
options[:content] = content_security_policy_nonce
|
21
|
+
tag("meta", options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
# = Action View CSRF Helper
|
3
|
-
module Helpers
|
5
|
+
module Helpers # :nodoc:
|
4
6
|
module CsrfHelper
|
5
7
|
# Returns meta tags "csrf-param" and "csrf-token" with the name of the cross-site
|
6
8
|
# request forgery protection parameter and token, respectively.
|
@@ -14,14 +16,14 @@ module ActionView
|
|
14
16
|
#
|
15
17
|
# You don't need to use these tags for regular forms as they generate their own hidden fields.
|
16
18
|
#
|
17
|
-
# For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the
|
18
|
-
# "X-CSRF-Token" HTTP header. If you are using
|
19
|
+
# For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag and send as the
|
20
|
+
# "X-CSRF-Token" HTTP header. If you are using rails-ujs this happens automatically.
|
19
21
|
#
|
20
22
|
def csrf_meta_tags
|
21
|
-
if protect_against_forgery?
|
23
|
+
if defined?(protect_against_forgery?) && protect_against_forgery?
|
22
24
|
[
|
23
|
-
tag(
|
24
|
-
tag(
|
25
|
+
tag("meta", name: "csrf-param", content: request_forgery_protection_token),
|
26
|
+
tag("meta", name: "csrf-token", content: form_authenticity_token)
|
25
27
|
].join("\n").html_safe
|
26
28
|
end
|
27
29
|
end
|