actionview 5.1.4 → 6.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +199 -168
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -5
- data/lib/action_view.rb +10 -4
- data/lib/action_view/base.rb +87 -23
- data/lib/action_view/buffers.rb +17 -0
- data/lib/action_view/cache_expiry.rb +52 -0
- data/lib/action_view/context.rb +7 -11
- data/lib/action_view/dependency_tracker.rb +12 -4
- data/lib/action_view/digestor.rb +24 -23
- data/lib/action_view/flows.rb +2 -1
- data/lib/action_view/gem_version.rb +4 -2
- data/lib/action_view/helpers.rb +4 -2
- data/lib/action_view/helpers/active_model_helper.rb +9 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +220 -57
- data/lib/action_view/helpers/asset_url_helper.rb +28 -23
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -2
- data/lib/action_view/helpers/cache_helper.rb +39 -28
- data/lib/action_view/helpers/capture_helper.rb +13 -7
- data/lib/action_view/helpers/controller_helper.rb +3 -1
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +5 -3
- data/lib/action_view/helpers/date_helper.rb +78 -33
- data/lib/action_view/helpers/debug_helper.rb +4 -2
- data/lib/action_view/helpers/form_helper.rb +357 -106
- data/lib/action_view/helpers/form_options_helper.rb +45 -39
- data/lib/action_view/helpers/form_tag_helper.rb +42 -27
- data/lib/action_view/helpers/javascript_helper.rb +28 -12
- data/lib/action_view/helpers/number_helper.rb +16 -8
- data/lib/action_view/helpers/output_safety_helper.rb +3 -1
- data/lib/action_view/helpers/rendering_helper.rb +20 -9
- data/lib/action_view/helpers/sanitize_helper.rb +15 -19
- data/lib/action_view/helpers/tag_helper.rb +100 -24
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/tags/base.rb +30 -21
- data/lib/action_view/helpers/tags/check_box.rb +3 -2
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +2 -1
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +2 -1
- data/lib/action_view/helpers/tags/collection_select.rb +3 -1
- 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 +5 -4
- data/lib/action_view/helpers/tags/datetime_field.rb +3 -2
- 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 +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -1
- data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
- data/lib/action_view/helpers/tags/label.rb +6 -5
- 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 +2 -0
- data/lib/action_view/helpers/tags/placeholderable.rb +2 -0
- data/lib/action_view/helpers/tags/radio_button.rb +3 -2
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +2 -0
- data/lib/action_view/helpers/tags/select.rb +4 -3
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +3 -1
- data/lib/action_view/helpers/tags/text_field.rb +3 -2
- data/lib/action_view/helpers/tags/time_field.rb +3 -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 +3 -6
- 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/text_helper.rb +11 -10
- data/lib/action_view/helpers/translation_helper.rb +102 -52
- data/lib/action_view/helpers/url_helper.rb +150 -32
- data/lib/action_view/layouts.rb +15 -15
- data/lib/action_view/log_subscriber.rb +32 -15
- data/lib/action_view/lookup_context.rb +67 -39
- data/lib/action_view/model_naming.rb +2 -0
- data/lib/action_view/path_set.rb +5 -12
- data/lib/action_view/railtie.rb +46 -21
- data/lib/action_view/record_identifier.rb +4 -3
- data/lib/action_view/renderer/abstract_renderer.rb +144 -11
- 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.rb +33 -283
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +64 -17
- data/lib/action_view/renderer/renderer.rb +61 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +14 -8
- data/lib/action_view/renderer/template_renderer.rb +36 -26
- data/lib/action_view/rendering.rb +57 -38
- data/lib/action_view/routing_url_for.rb +15 -12
- data/lib/action_view/tasks/cache_digests.rake +2 -0
- data/lib/action_view/template.rb +69 -76
- data/lib/action_view/template/error.rb +32 -18
- data/lib/action_view/template/handlers.rb +4 -2
- data/lib/action_view/template/handlers/builder.rb +5 -6
- data/lib/action_view/template/handlers/erb.rb +20 -19
- data/lib/action_view/template/handlers/erb/erubi.rb +17 -9
- data/lib/action_view/template/handlers/html.rb +3 -1
- data/lib/action_view/template/handlers/raw.rb +4 -2
- data/lib/action_view/template/html.rb +8 -7
- 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 +194 -152
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/text.rb +5 -4
- data/lib/action_view/template/types.rb +3 -1
- data/lib/action_view/test_case.rb +38 -30
- data/lib/action_view/testing/resolvers.rb +20 -27
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +2 -0
- data/lib/action_view/view_paths.rb +61 -40
- data/lib/assets/compiled/rails-ujs.js +84 -23
- metadata +34 -23
- data/lib/action_view/helpers/record_tag_helper.rb +0 -21
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +0 -9
- data/lib/action_view/template/handlers/erb/erubis.rb +0 -81
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
1
5
|
module ActionView
|
2
6
|
module CollectionCaching # :nodoc:
|
3
7
|
extend ActiveSupport::Concern
|
@@ -5,48 +9,91 @@ module ActionView
|
|
5
9
|
included do
|
6
10
|
# Fallback cache store if Action View is used without Rails.
|
7
11
|
# Otherwise overridden in Railtie to use Rails.cache.
|
8
|
-
mattr_accessor
|
12
|
+
mattr_accessor :collection_cache, default: ActiveSupport::Cache::MemoryStore.new
|
9
13
|
end
|
10
14
|
|
11
15
|
private
|
12
|
-
def
|
13
|
-
|
16
|
+
def will_cache?(options, view)
|
17
|
+
options[:cached] && view.controller.respond_to?(:perform_caching) && view.controller.perform_caching
|
18
|
+
end
|
19
|
+
|
20
|
+
def cache_collection_render(instrumentation_payload, view, template, collection)
|
21
|
+
return yield(collection) unless will_cache?(@options, view)
|
22
|
+
|
23
|
+
collection_iterator = collection
|
14
24
|
|
15
|
-
|
16
|
-
|
25
|
+
# Result is a hash with the key represents the
|
26
|
+
# key used for cache lookup and the value is the item
|
27
|
+
# on which the partial is being rendered
|
28
|
+
keyed_collection, ordered_keys = collection_by_cache_keys(view, template, collection)
|
29
|
+
|
30
|
+
# Pull all partials from cache
|
31
|
+
# Result is a hash, key matches the entry in
|
32
|
+
# `keyed_collection` where the cache was retrieved and the
|
33
|
+
# value is the value that was present in the cache
|
34
|
+
cached_partials = collection_cache.read_multi(*keyed_collection.keys)
|
17
35
|
instrumentation_payload[:cache_hits] = cached_partials.size
|
18
36
|
|
19
|
-
|
20
|
-
|
37
|
+
# Extract the items for the keys that are not found
|
38
|
+
collection = keyed_collection.reject { |key, _| cached_partials.key?(key) }.values
|
39
|
+
|
40
|
+
rendered_partials = collection.empty? ? [] : yield(collection_iterator.from_collection(collection))
|
21
41
|
|
22
42
|
index = 0
|
23
|
-
fetch_or_cache_partial(cached_partials, order_by: keyed_collection.each_key) do
|
43
|
+
keyed_partials = fetch_or_cache_partial(cached_partials, template, order_by: keyed_collection.each_key) do
|
44
|
+
# This block is called once
|
45
|
+
# for every cache miss while preserving order.
|
24
46
|
rendered_partials[index].tap { index += 1 }
|
25
47
|
end
|
48
|
+
|
49
|
+
ordered_keys.map do |key|
|
50
|
+
keyed_partials[key]
|
51
|
+
end
|
26
52
|
end
|
27
53
|
|
28
54
|
def callable_cache_key?
|
29
55
|
@options[:cached].respond_to?(:call)
|
30
56
|
end
|
31
57
|
|
32
|
-
def collection_by_cache_keys
|
58
|
+
def collection_by_cache_keys(view, template, collection)
|
33
59
|
seed = callable_cache_key? ? @options[:cached] : ->(i) { i }
|
34
60
|
|
35
|
-
|
36
|
-
|
61
|
+
digest_path = view.digest_path_from_template(template)
|
62
|
+
|
63
|
+
collection.each_with_object([{}, []]) do |item, (hash, ordered_keys)|
|
64
|
+
key = expanded_cache_key(seed.call(item), view, template, digest_path)
|
65
|
+
ordered_keys << key
|
66
|
+
hash[key] = item
|
37
67
|
end
|
38
68
|
end
|
39
69
|
|
40
|
-
def expanded_cache_key(key)
|
41
|
-
key =
|
70
|
+
def expanded_cache_key(key, view, template, digest_path)
|
71
|
+
key = view.combined_fragment_cache_key(view.cache_fragment_name(key, digest_path: digest_path))
|
42
72
|
key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
|
43
73
|
end
|
44
74
|
|
45
|
-
|
46
|
-
|
47
|
-
|
75
|
+
# `order_by` is an enumerable object containing keys of the cache,
|
76
|
+
# all keys are passed in whether found already or not.
|
77
|
+
#
|
78
|
+
# `cached_partials` is a hash. If the value exists
|
79
|
+
# it represents the rendered partial from the cache
|
80
|
+
# otherwise `Hash#fetch` will take the value of its block.
|
81
|
+
#
|
82
|
+
# This method expects a block that will return the rendered
|
83
|
+
# partial. An example is to render all results
|
84
|
+
# for each element that was not found in the cache and store it as an array.
|
85
|
+
# Order it so that the first empty cache element in `cached_partials`
|
86
|
+
# corresponds to the first element in `rendered_partials`.
|
87
|
+
#
|
88
|
+
# If the partial is not already cached it will also be
|
89
|
+
# written back to the underlying cache store.
|
90
|
+
def fetch_or_cache_partial(cached_partials, template, order_by:)
|
91
|
+
order_by.index_with do |cache_key|
|
92
|
+
if content = cached_partials[cache_key]
|
93
|
+
build_rendered_template(content, template)
|
94
|
+
else
|
48
95
|
yield.tap do |rendered_partial|
|
49
|
-
collection_cache.write(cache_key, rendered_partial)
|
96
|
+
collection_cache.write(cache_key, rendered_partial.body)
|
50
97
|
end
|
51
98
|
end
|
52
99
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
# This is the main entry point for rendering. It basically delegates
|
3
5
|
# to other objects like TemplateRenderer and PartialRenderer which
|
@@ -17,10 +19,14 @@ module ActionView
|
|
17
19
|
|
18
20
|
# Main render entry point shared by Action View and Action Controller.
|
19
21
|
def render(context, options)
|
22
|
+
render_to_object(context, options).body
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_to_object(context, options) # :nodoc:
|
20
26
|
if options.key?(:partial)
|
21
|
-
|
27
|
+
render_partial_to_object(context, options)
|
22
28
|
else
|
23
|
-
|
29
|
+
render_template_to_object(context, options)
|
24
30
|
end
|
25
31
|
end
|
26
32
|
|
@@ -39,16 +45,67 @@ module ActionView
|
|
39
45
|
|
40
46
|
# Direct access to template rendering.
|
41
47
|
def render_template(context, options) #:nodoc:
|
42
|
-
|
48
|
+
render_template_to_object(context, options).body
|
43
49
|
end
|
44
50
|
|
45
51
|
# Direct access to partial rendering.
|
46
52
|
def render_partial(context, options, &block) #:nodoc:
|
47
|
-
|
53
|
+
render_partial_to_object(context, options, &block).body
|
48
54
|
end
|
49
55
|
|
50
56
|
def cache_hits # :nodoc:
|
51
57
|
@cache_hits ||= {}
|
52
58
|
end
|
59
|
+
|
60
|
+
def render_template_to_object(context, options) #:nodoc:
|
61
|
+
TemplateRenderer.new(@lookup_context).render(context, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_partial_to_object(context, options, &block) #:nodoc:
|
65
|
+
partial = options[:partial]
|
66
|
+
if String === partial
|
67
|
+
collection = collection_from_options(options)
|
68
|
+
|
69
|
+
if collection
|
70
|
+
# Collection + Partial
|
71
|
+
renderer = CollectionRenderer.new(@lookup_context, options)
|
72
|
+
renderer.render_collection_with_partial(collection, partial, context, block)
|
73
|
+
else
|
74
|
+
if options.key?(:object)
|
75
|
+
# Object + Partial
|
76
|
+
renderer = ObjectRenderer.new(@lookup_context, options)
|
77
|
+
renderer.render_object_with_partial(options[:object], partial, context, block)
|
78
|
+
else
|
79
|
+
# Partial
|
80
|
+
renderer = PartialRenderer.new(@lookup_context, options)
|
81
|
+
renderer.render(partial, context, block)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
collection = collection_from_object(partial) || collection_from_options(options)
|
86
|
+
|
87
|
+
if collection
|
88
|
+
# Collection + Derived Partial
|
89
|
+
renderer = CollectionRenderer.new(@lookup_context, options)
|
90
|
+
renderer.render_collection_derive_partial(collection, context, block)
|
91
|
+
else
|
92
|
+
# Object + Derived Partial
|
93
|
+
renderer = ObjectRenderer.new(@lookup_context, options)
|
94
|
+
renderer.render_object_derive_partial(partial, context, block)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def collection_from_options(options)
|
101
|
+
if options.key?(:collection)
|
102
|
+
collection = options[:collection]
|
103
|
+
collection || []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def collection_from_object(object)
|
108
|
+
object if object.respond_to?(:to_ary)
|
109
|
+
end
|
53
110
|
end
|
54
111
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "fiber"
|
2
4
|
|
3
5
|
module ActionView
|
@@ -25,14 +27,13 @@ module ActionView
|
|
25
27
|
end
|
26
28
|
|
27
29
|
private
|
28
|
-
|
29
30
|
# This is the same logging logic as in ShowExceptions middleware.
|
30
31
|
def log_error(exception)
|
31
32
|
logger = ActionView::Base.logger
|
32
33
|
return unless logger
|
33
34
|
|
34
|
-
message = "\n#{exception.class} (#{exception.message}):\n"
|
35
|
-
message << exception.
|
35
|
+
message = +"\n#{exception.class} (#{exception.message}):\n"
|
36
|
+
message << exception.annotated_source_code.to_s if exception.respond_to?(:annotated_source_code)
|
36
37
|
message << " " << exception.backtrace.join("\n ")
|
37
38
|
logger.fatal("#{message}\n\n")
|
38
39
|
end
|
@@ -41,19 +42,18 @@ module ActionView
|
|
41
42
|
# For streaming, instead of rendering a given a template, we return a Body
|
42
43
|
# object that responds to each. This object is initialized with a block
|
43
44
|
# that knows how to render the template.
|
44
|
-
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
|
45
|
-
return [super] unless layout_name && template.supports_streaming?
|
45
|
+
def render_template(view, template, layout_name = nil, locals = {}) #:nodoc:
|
46
|
+
return [super.body] unless layout_name && template.supports_streaming?
|
46
47
|
|
47
48
|
locals ||= {}
|
48
49
|
layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
|
49
50
|
|
50
51
|
Body.new do |buffer|
|
51
|
-
delayed_render(buffer, template, layout,
|
52
|
+
delayed_render(buffer, template, layout, view, locals)
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
55
56
|
private
|
56
|
-
|
57
57
|
def delayed_render(buffer, template, layout, view, locals)
|
58
58
|
# Wrap the given buffer in the StreamingBuffer and pass it to the
|
59
59
|
# underlying template handler. Now, every time something is concatenated
|
@@ -62,8 +62,14 @@ module ActionView
|
|
62
62
|
output = ActionView::StreamingBuffer.new(buffer)
|
63
63
|
yielder = lambda { |*name| view._layout_for(*name) }
|
64
64
|
|
65
|
-
instrument(
|
65
|
+
ActiveSupport::Notifications.instrument(
|
66
|
+
"render_template.action_view",
|
67
|
+
identifier: template.identifier,
|
68
|
+
layout: layout && layout.virtual_path
|
69
|
+
) do
|
70
|
+
outer_config = I18n.config
|
66
71
|
fiber = Fiber.new do
|
72
|
+
I18n.config = outer_config
|
67
73
|
if layout
|
68
74
|
layout.render(view, locals, output, &yielder)
|
69
75
|
else
|
@@ -1,21 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionView
|
4
4
|
class TemplateRenderer < AbstractRenderer #:nodoc:
|
5
5
|
def render(context, options)
|
6
|
-
@view = context
|
7
6
|
@details = extract_details(options)
|
8
7
|
template = determine_template(options)
|
9
8
|
|
10
|
-
prepend_formats(template.
|
9
|
+
prepend_formats(template.format)
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
render_template(template, options[:layout], options[:locals])
|
11
|
+
render_template(context, template, options[:layout], options[:locals] || {})
|
15
12
|
end
|
16
13
|
|
17
14
|
private
|
18
|
-
|
19
15
|
# Determine the template to be rendered using the given options.
|
20
16
|
def determine_template(options)
|
21
17
|
keys = options.has_key?(:locals) ? options[:locals].keys : []
|
@@ -27,15 +23,26 @@ module ActionView
|
|
27
23
|
elsif options.key?(:html)
|
28
24
|
Template::HTML.new(options[:html], formats.first)
|
29
25
|
elsif options.key?(:file)
|
30
|
-
|
26
|
+
if File.exist?(options[:file])
|
27
|
+
Template::RawFile.new(options[:file])
|
28
|
+
else
|
29
|
+
raise ArgumentError, "`render file:` should be given the absolute path to a file. '#{options[:file]}' was given instead"
|
30
|
+
end
|
31
31
|
elsif options.key?(:inline)
|
32
32
|
handler = Template.handler_for_extension(options[:type] || "erb")
|
33
|
-
|
33
|
+
format = if handler.respond_to?(:default_format)
|
34
|
+
handler.default_format
|
35
|
+
else
|
36
|
+
@lookup_context.formats.first
|
37
|
+
end
|
38
|
+
Template::Inline.new(options[:inline], "inline template", handler, locals: keys, format: format)
|
39
|
+
elsif options.key?(:renderable)
|
40
|
+
Template::Renderable.new(options[:renderable])
|
34
41
|
elsif options.key?(:template)
|
35
42
|
if options[:template].respond_to?(:render)
|
36
43
|
options[:template]
|
37
44
|
else
|
38
|
-
find_template(options[:template], options[:prefixes], false, keys, @details)
|
45
|
+
@lookup_context.find_template(options[:template], options[:prefixes], false, keys, @details)
|
39
46
|
end
|
40
47
|
else
|
41
48
|
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option."
|
@@ -44,27 +51,30 @@ module ActionView
|
|
44
51
|
|
45
52
|
# Renders the given template. A string representing the layout can be
|
46
53
|
# supplied as well.
|
47
|
-
def render_template(template, layout_name
|
48
|
-
view,
|
49
|
-
|
50
|
-
|
51
|
-
|
54
|
+
def render_template(view, template, layout_name, locals)
|
55
|
+
render_with_layout(view, template, layout_name, locals) do |layout|
|
56
|
+
ActiveSupport::Notifications.instrument(
|
57
|
+
"render_template.action_view",
|
58
|
+
identifier: template.identifier,
|
59
|
+
layout: layout && layout.virtual_path
|
60
|
+
) do
|
52
61
|
template.render(view, locals) { |*name| view._layout_for(*name) }
|
53
62
|
end
|
54
63
|
end
|
55
64
|
end
|
56
65
|
|
57
|
-
def render_with_layout(path, locals)
|
66
|
+
def render_with_layout(view, template, path, locals)
|
58
67
|
layout = path && find_layout(path, locals.keys, [formats.first])
|
59
|
-
content = yield(layout)
|
60
68
|
|
61
|
-
if layout
|
62
|
-
|
63
|
-
|
64
|
-
|
69
|
+
body = if layout
|
70
|
+
ActiveSupport::Notifications.instrument("render_layout.action_view", identifier: layout.identifier) do
|
71
|
+
view.view_flow.set(:layout, yield(layout))
|
72
|
+
layout.render(view, locals) { |*name| view._layout_for(*name) }
|
73
|
+
end
|
65
74
|
else
|
66
|
-
|
75
|
+
yield
|
67
76
|
end
|
77
|
+
build_rendered_template(body, template)
|
68
78
|
end
|
69
79
|
|
70
80
|
# This is the method which actually finds the layout using details in the lookup
|
@@ -82,16 +92,16 @@ module ActionView
|
|
82
92
|
when String
|
83
93
|
begin
|
84
94
|
if layout.start_with?("/")
|
85
|
-
|
95
|
+
raise ArgumentError, "Rendering layouts from an absolute path is not supported."
|
86
96
|
else
|
87
|
-
find_template(layout, nil, false, [], details)
|
97
|
+
@lookup_context.find_template(layout, nil, false, [], details)
|
88
98
|
end
|
89
99
|
rescue ActionView::MissingTemplate
|
90
100
|
all_details = @details.merge(formats: @lookup_context.default_formats)
|
91
|
-
raise unless template_exists?(layout, nil, false, [], all_details)
|
101
|
+
raise unless template_exists?(layout, nil, false, [], **all_details)
|
92
102
|
end
|
93
103
|
when Proc
|
94
|
-
resolve_layout(layout.call(formats), keys, formats)
|
104
|
+
resolve_layout(layout.call(@lookup_context, formats), keys, formats)
|
95
105
|
else
|
96
106
|
layout
|
97
107
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "action_view/view_paths"
|
2
4
|
|
3
5
|
module ActionView
|
@@ -24,7 +26,14 @@ module ActionView
|
|
24
26
|
extend ActiveSupport::Concern
|
25
27
|
include ActionView::ViewPaths
|
26
28
|
|
27
|
-
|
29
|
+
attr_reader :rendered_format
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@rendered_format = nil
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
# Overwrite process to set up I18n proxy.
|
28
37
|
def process(*) #:nodoc:
|
29
38
|
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
30
39
|
super
|
@@ -33,48 +42,59 @@ module ActionView
|
|
33
42
|
end
|
34
43
|
|
35
44
|
module ClassMethods
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
def _routes
|
46
|
+
end
|
47
|
+
|
48
|
+
def _helpers
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_view_context_class(klass, supports_path, routes, helpers)
|
52
|
+
Class.new(klass) do
|
53
|
+
if routes
|
54
|
+
include routes.url_helpers(supports_path)
|
55
|
+
include routes.mounted_helpers
|
56
|
+
end
|
57
|
+
|
58
|
+
if helpers
|
59
|
+
include helpers
|
51
60
|
end
|
52
61
|
end
|
53
62
|
end
|
54
|
-
end
|
55
63
|
|
56
|
-
|
64
|
+
def view_context_class
|
65
|
+
klass = ActionView::LookupContext::DetailsKey.view_context_class(ActionView::Base)
|
66
|
+
|
67
|
+
@view_context_class ||= build_view_context_class(klass, supports_path?, _routes, _helpers)
|
68
|
+
|
69
|
+
if klass.changed?(@view_context_class)
|
70
|
+
@view_context_class = build_view_context_class(klass, supports_path?, _routes, _helpers)
|
71
|
+
end
|
72
|
+
|
73
|
+
@view_context_class
|
74
|
+
end
|
75
|
+
end
|
57
76
|
|
58
77
|
def view_context_class
|
59
|
-
|
78
|
+
self.class.view_context_class
|
60
79
|
end
|
61
80
|
|
62
81
|
# An instance of a view class. The default view class is ActionView::Base.
|
63
82
|
#
|
64
83
|
# The view class must have the following methods:
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
84
|
+
#
|
85
|
+
# * <tt>View.new(lookup_context, assigns, controller)</tt> — Create a new
|
86
|
+
# ActionView instance for a controller and we can also pass the arguments.
|
87
|
+
#
|
88
|
+
# * <tt>View#render(option)</tt> — Returns String with the rendered template.
|
69
89
|
#
|
70
90
|
# Override this method in a module to change the default behavior.
|
71
91
|
def view_context
|
72
|
-
view_context_class.new(
|
92
|
+
view_context_class.new(lookup_context, view_assigns, self)
|
73
93
|
end
|
74
94
|
|
75
95
|
# Returns an object that is able to render templates.
|
76
|
-
# :
|
77
|
-
|
96
|
+
def view_renderer # :nodoc:
|
97
|
+
# Lifespan: Per controller
|
78
98
|
@_view_renderer ||= ActionView::Renderer.new(lookup_context)
|
79
99
|
end
|
80
100
|
|
@@ -83,36 +103,34 @@ module ActionView
|
|
83
103
|
_render_template(options)
|
84
104
|
end
|
85
105
|
|
86
|
-
def rendered_format
|
87
|
-
Template::Types[lookup_context.rendered_format]
|
88
|
-
end
|
89
|
-
|
90
106
|
private
|
91
|
-
|
92
107
|
# Find and render a template based on the options given.
|
93
|
-
# :api: private
|
94
108
|
def _render_template(options)
|
95
109
|
variant = options.delete(:variant)
|
96
110
|
assigns = options.delete(:assigns)
|
97
111
|
context = view_context
|
98
112
|
|
99
113
|
context.assign assigns if assigns
|
100
|
-
lookup_context.rendered_format = nil if options[:formats]
|
101
114
|
lookup_context.variants = variant if variant
|
102
115
|
|
103
|
-
|
116
|
+
rendered_template = context.in_rendering_context(options) do |renderer|
|
117
|
+
renderer.render_to_object(context, options)
|
118
|
+
end
|
119
|
+
|
120
|
+
rendered_format = rendered_template.format || lookup_context.formats.first
|
121
|
+
@rendered_format = Template::Types[rendered_format]
|
122
|
+
|
123
|
+
rendered_template.body
|
104
124
|
end
|
105
125
|
|
106
126
|
# Assign the rendered format to look up context.
|
107
127
|
def _process_format(format)
|
108
128
|
super
|
109
|
-
lookup_context.formats = [format.to_sym]
|
110
|
-
lookup_context.rendered_format = lookup_context.formats.first
|
129
|
+
lookup_context.formats = [format.to_sym] if format.to_sym
|
111
130
|
end
|
112
131
|
|
113
132
|
# Normalize args by converting render "foo" to render :action => "foo" and
|
114
133
|
# render "foo/bar" to render :template => "foo/bar".
|
115
|
-
# :api: private
|
116
134
|
def _normalize_args(action = nil, options = {})
|
117
135
|
options = super(action, options)
|
118
136
|
case action
|
@@ -126,6 +144,8 @@ module ActionView
|
|
126
144
|
else
|
127
145
|
if action.respond_to?(:permitted?) && action.permitted?
|
128
146
|
options = action
|
147
|
+
elsif action.respond_to?(:render_in)
|
148
|
+
options[:renderable] = action
|
129
149
|
else
|
130
150
|
options[:partial] = action
|
131
151
|
end
|
@@ -135,7 +155,6 @@ module ActionView
|
|
135
155
|
end
|
136
156
|
|
137
157
|
# Normalize options.
|
138
|
-
# :api: private
|
139
158
|
def _normalize_options(options)
|
140
159
|
options = super(options)
|
141
160
|
if options[:partial] == true
|