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,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
|
@@ -15,16 +17,16 @@ module ActionView
|
|
15
17
|
@lookup_context = lookup_context
|
16
18
|
end
|
17
19
|
|
18
|
-
# Main render entry point shared by
|
20
|
+
# Main render entry point shared by Action View and Action Controller.
|
19
21
|
def render(context, options)
|
20
|
-
|
21
|
-
|
22
|
-
end
|
22
|
+
render_to_object(context, options).body
|
23
|
+
end
|
23
24
|
|
25
|
+
def render_to_object(context, options) # :nodoc:
|
24
26
|
if options.key?(:partial)
|
25
|
-
|
27
|
+
render_partial_to_object(context, options)
|
26
28
|
else
|
27
|
-
|
29
|
+
render_template_to_object(context, options)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
@@ -41,14 +43,69 @@ module ActionView
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
# Direct
|
45
|
-
def render_template(context, options)
|
46
|
-
|
46
|
+
# Direct access to template rendering.
|
47
|
+
def render_template(context, options) # :nodoc:
|
48
|
+
render_template_to_object(context, options).body
|
47
49
|
end
|
48
50
|
|
49
51
|
# Direct access to partial rendering.
|
50
|
-
def render_partial(context, options, &block)
|
51
|
-
|
52
|
+
def render_partial(context, options, &block) # :nodoc:
|
53
|
+
render_partial_to_object(context, options, &block).body
|
54
|
+
end
|
55
|
+
|
56
|
+
def cache_hits # :nodoc:
|
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,16 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fiber"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
# == TODO
|
5
7
|
#
|
6
8
|
# * Support streaming from child templates, partials and so on.
|
7
|
-
# * Integrate exceptions with exceptron
|
8
9
|
# * Rack::Cache needs to support streaming bodies
|
9
|
-
class StreamingTemplateRenderer < TemplateRenderer
|
10
|
+
class StreamingTemplateRenderer < TemplateRenderer # :nodoc:
|
10
11
|
# A valid Rack::Body (i.e. it responds to each).
|
11
12
|
# It is initialized with a block that, when called, starts
|
12
13
|
# rendering the template.
|
13
|
-
class Body
|
14
|
+
class Body # :nodoc:
|
14
15
|
def initialize(&start)
|
15
16
|
@start = start
|
16
17
|
end
|
@@ -26,78 +27,81 @@ module ActionView
|
|
26
27
|
end
|
27
28
|
|
28
29
|
private
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
logger.fatal("#{message}\n\n")
|
40
|
-
end
|
30
|
+
# This is the same logging logic as in ShowExceptions middleware.
|
31
|
+
def log_error(exception)
|
32
|
+
logger = ActionView::Base.logger
|
33
|
+
return unless logger
|
34
|
+
|
35
|
+
message = +"\n#{exception.class} (#{exception.message}):\n"
|
36
|
+
message << exception.annotated_source_code.to_s if exception.respond_to?(:annotated_source_code)
|
37
|
+
message << " " << exception.backtrace.join("\n ")
|
38
|
+
logger.fatal("#{message}\n\n")
|
39
|
+
end
|
41
40
|
end
|
42
41
|
|
43
42
|
# For streaming, instead of rendering a given a template, we return a Body
|
44
43
|
# object that responds to each. This object is initialized with a block
|
45
44
|
# that knows how to render the template.
|
46
|
-
def render_template(template, layout_name = nil, locals = {})
|
47
|
-
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?
|
48
47
|
|
49
48
|
locals ||= {}
|
50
|
-
layout = layout_name && find_layout(layout_name, locals.keys)
|
49
|
+
layout = layout_name && find_layout(layout_name, locals.keys, [formats.first])
|
51
50
|
|
52
51
|
Body.new do |buffer|
|
53
|
-
delayed_render(buffer, template, layout,
|
52
|
+
delayed_render(buffer, template, layout, view, locals)
|
54
53
|
end
|
55
54
|
end
|
56
55
|
|
57
56
|
private
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
57
|
+
def delayed_render(buffer, template, layout, view, locals)
|
58
|
+
# Wrap the given buffer in the StreamingBuffer and pass it to the
|
59
|
+
# underlying template handler. Now, every time something is concatenated
|
60
|
+
# to the buffer, it is not appended to an array, but streamed straight
|
61
|
+
# to the client.
|
62
|
+
output = ActionView::StreamingBuffer.new(buffer)
|
63
|
+
yielder = lambda { |*name| view._layout_for(*name) }
|
64
|
+
|
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
|
71
|
+
fiber = Fiber.new do
|
72
|
+
I18n.config = outer_config
|
73
|
+
if layout
|
74
|
+
layout.render(view, locals, output, &yielder)
|
75
|
+
else
|
76
|
+
# If you don't have a layout, just render the thing
|
77
|
+
# and concatenate the final result. This is the same
|
78
|
+
# as a layout with just <%= yield %>
|
79
|
+
output.safe_concat view._layout_for
|
80
|
+
end
|
76
81
|
end
|
77
|
-
end
|
78
82
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
+
# Set the view flow to support streaming. It will be aware
|
84
|
+
# when to stop rendering the layout because it needs to search
|
85
|
+
# something in the template and vice-versa.
|
86
|
+
view.view_flow = StreamingFlow.new(view, fiber)
|
83
87
|
|
84
|
-
|
85
|
-
|
88
|
+
# Yo! Start the fiber!
|
89
|
+
fiber.resume
|
86
90
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
91
|
+
# If the fiber is still alive, it means we need something
|
92
|
+
# from the template, so start rendering it. If not, it means
|
93
|
+
# the layout exited without requiring anything from the template.
|
94
|
+
if fiber.alive?
|
95
|
+
content = template.render(view, locals, &yielder)
|
92
96
|
|
93
|
-
|
94
|
-
|
97
|
+
# Once rendering the template is done, sets its content in the :layout key.
|
98
|
+
view.view_flow.set(:layout, content)
|
95
99
|
|
96
|
-
|
97
|
-
|
98
|
-
|
100
|
+
# In case the layout continues yielding, we need to resume
|
101
|
+
# the fiber until all yields are handled.
|
102
|
+
fiber.resume while fiber.alive?
|
103
|
+
end
|
99
104
|
end
|
100
105
|
end
|
101
|
-
end
|
102
106
|
end
|
103
107
|
end
|
@@ -1,101 +1,114 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionView
|
4
|
-
class TemplateRenderer < AbstractRenderer
|
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
|
15
|
+
# Determine the template to be rendered using the given options.
|
16
|
+
def determine_template(options)
|
17
|
+
keys = options.has_key?(:locals) ? options[:locals].keys : []
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
19
|
+
if options.key?(:body)
|
20
|
+
Template::Text.new(options[:body])
|
21
|
+
elsif options.key?(:plain)
|
22
|
+
Template::Text.new(options[:plain])
|
23
|
+
elsif options.key?(:html)
|
24
|
+
Template::HTML.new(options[:html], formats.first)
|
25
|
+
elsif options.key?(:file)
|
26
|
+
if File.exist?(options[:file])
|
27
|
+
Template::RawFile.new(options[:file])
|
28
|
+
else
|
29
|
+
if Pathname.new(options[:file]).absolute?
|
30
|
+
raise ArgumentError, "File #{options[:file]} does not exist"
|
31
|
+
else
|
32
|
+
raise ArgumentError, "`render file:` should be given the absolute path to a file. '#{options[:file]}' was given instead"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
elsif options.key?(:inline)
|
36
|
+
handler = Template.handler_for_extension(options[:type] || "erb")
|
37
|
+
format = if handler.respond_to?(:default_format)
|
38
|
+
handler.default_format
|
39
|
+
else
|
40
|
+
@lookup_context.formats.first
|
41
|
+
end
|
42
|
+
Template::Inline.new(options[:inline], "inline template", handler, locals: keys, format: format)
|
43
|
+
elsif options.key?(:renderable)
|
44
|
+
Template::Renderable.new(options[:renderable])
|
45
|
+
elsif options.key?(:template)
|
46
|
+
if options[:template].respond_to?(:render)
|
47
|
+
options[:template]
|
48
|
+
else
|
49
|
+
@lookup_context.find_template(options[:template], options[:prefixes], false, keys, @details)
|
50
|
+
end
|
39
51
|
else
|
40
|
-
|
52
|
+
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option."
|
41
53
|
end
|
42
|
-
else
|
43
|
-
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :text or :body option."
|
44
54
|
end
|
45
|
-
end
|
46
55
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
56
|
+
# Renders the given template. A string representing the layout can be
|
57
|
+
# supplied as well.
|
58
|
+
def render_template(view, template, layout_name, locals)
|
59
|
+
render_with_layout(view, template, layout_name, locals) do |layout|
|
60
|
+
ActiveSupport::Notifications.instrument(
|
61
|
+
"render_template.action_view",
|
62
|
+
identifier: template.identifier,
|
63
|
+
layout: layout && layout.virtual_path
|
64
|
+
) do
|
65
|
+
template.render(view, locals) { |*name| view._layout_for(*name) }
|
66
|
+
end
|
55
67
|
end
|
56
68
|
end
|
57
|
-
end
|
58
69
|
|
59
|
-
|
60
|
-
|
61
|
-
content = yield(layout)
|
70
|
+
def render_with_layout(view, template, path, locals)
|
71
|
+
layout = path && find_layout(path, locals.keys, [formats.first])
|
62
72
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
73
|
+
body = if layout
|
74
|
+
ActiveSupport::Notifications.instrument("render_layout.action_view", identifier: layout.identifier) do
|
75
|
+
view.view_flow.set(:layout, yield(layout))
|
76
|
+
layout.render(view, locals) { |*name| view._layout_for(*name) }
|
77
|
+
end
|
78
|
+
else
|
79
|
+
yield
|
80
|
+
end
|
81
|
+
build_rendered_template(body, template)
|
69
82
|
end
|
70
|
-
end
|
71
83
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
84
|
+
# This is the method which actually finds the layout using details in the lookup
|
85
|
+
# context object. If no layout is found, it checks if at least a layout with
|
86
|
+
# the given name exists across all details before raising the error.
|
87
|
+
def find_layout(layout, keys, formats)
|
88
|
+
resolve_layout(layout, keys, formats)
|
89
|
+
end
|
78
90
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
91
|
+
def resolve_layout(layout, keys, formats)
|
92
|
+
details = @details.dup
|
93
|
+
details[:formats] = formats
|
94
|
+
|
95
|
+
case layout
|
96
|
+
when String
|
97
|
+
begin
|
98
|
+
if layout.start_with?("/")
|
99
|
+
raise ArgumentError, "Rendering layouts from an absolute path is not supported."
|
100
|
+
else
|
101
|
+
@lookup_context.find_template(layout, nil, false, [], details)
|
102
|
+
end
|
103
|
+
rescue ActionView::MissingTemplate
|
104
|
+
all_details = @details.merge(formats: @lookup_context.default_formats)
|
105
|
+
raise unless template_exists?(layout, nil, false, [], **all_details)
|
87
106
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
107
|
+
when Proc
|
108
|
+
resolve_layout(layout.call(@lookup_context, formats), keys, formats)
|
109
|
+
else
|
110
|
+
layout
|
91
111
|
end
|
92
|
-
when Proc
|
93
|
-
resolve_layout(layout.call, keys)
|
94
|
-
when FalseClass
|
95
|
-
nil
|
96
|
-
else
|
97
|
-
layout
|
98
112
|
end
|
99
|
-
end
|
100
113
|
end
|
101
114
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "action_view/view_paths"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
|
5
7
|
# it will trigger the lookup_context and consequently expire the cache.
|
6
|
-
class I18nProxy < ::I18n::Config
|
8
|
+
class I18nProxy < ::I18n::Config # :nodoc:
|
7
9
|
attr_reader :original_config, :lookup_context
|
8
10
|
|
9
11
|
def initialize(original_config, lookup_context)
|
@@ -24,8 +26,15 @@ module ActionView
|
|
24
26
|
extend ActiveSupport::Concern
|
25
27
|
include ActionView::ViewPaths
|
26
28
|
|
27
|
-
|
28
|
-
|
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.
|
37
|
+
def process(*) # :nodoc:
|
29
38
|
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
30
39
|
super
|
31
40
|
ensure
|
@@ -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
|
-
# An instance of a view class. The default view class is ActionView::Base
|
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,34 +103,35 @@ module ActionView
|
|
83
103
|
_render_template(options)
|
84
104
|
end
|
85
105
|
|
86
|
-
def rendered_format
|
87
|
-
Mime[lookup_context.rendered_format]
|
88
|
-
end
|
89
|
-
|
90
106
|
private
|
91
|
-
|
92
107
|
# Find and render a template based on the options given.
|
93
|
-
|
94
|
-
|
95
|
-
|
108
|
+
def _render_template(options)
|
109
|
+
variant = options.delete(:variant)
|
110
|
+
assigns = options.delete(:assigns)
|
111
|
+
context = view_context
|
96
112
|
|
97
|
-
|
113
|
+
context.assign assigns if assigns
|
98
114
|
lookup_context.variants = variant if variant
|
99
115
|
|
100
|
-
|
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
|
101
124
|
end
|
102
125
|
|
103
|
-
# Assign the rendered format to
|
104
|
-
def _process_format(format
|
126
|
+
# Assign the rendered format to look up context.
|
127
|
+
def _process_format(format)
|
105
128
|
super
|
106
|
-
lookup_context.formats = [format.to_sym]
|
107
|
-
lookup_context.rendered_format = lookup_context.formats.first
|
129
|
+
lookup_context.formats = [format.to_sym] if format.to_sym
|
108
130
|
end
|
109
131
|
|
110
132
|
# Normalize args by converting render "foo" to render :action => "foo" and
|
111
133
|
# render "foo/bar" to render :template => "foo/bar".
|
112
|
-
|
113
|
-
def _normalize_args(action=nil, options={})
|
134
|
+
def _normalize_args(action = nil, options = {})
|
114
135
|
options = super(action, options)
|
115
136
|
case action
|
116
137
|
when NilClass
|
@@ -121,14 +142,19 @@ module ActionView
|
|
121
142
|
key = action.include?(?/) ? :template : :action
|
122
143
|
options[key] = action
|
123
144
|
else
|
124
|
-
|
145
|
+
if action.respond_to?(:permitted?) && action.permitted?
|
146
|
+
options = action
|
147
|
+
elsif action.respond_to?(:render_in)
|
148
|
+
options[:renderable] = action
|
149
|
+
else
|
150
|
+
options[:partial] = action
|
151
|
+
end
|
125
152
|
end
|
126
153
|
|
127
154
|
options
|
128
155
|
end
|
129
156
|
|
130
157
|
# Normalize options.
|
131
|
-
# :api: private
|
132
158
|
def _normalize_options(options)
|
133
159
|
options = super(options)
|
134
160
|
if options[:partial] == true
|