actionview 4.2.11.1 → 6.0.4.8

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.

Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +242 -186
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +144 -37
  6. data/lib/action_view/buffers.rb +18 -1
  7. data/lib/action_view/cache_expiry.rb +53 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +54 -20
  10. data/lib/action_view/digestor.rb +88 -85
  11. data/lib/action_view/flows.rb +11 -12
  12. data/lib/action_view/gem_version.rb +6 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +16 -11
  14. data/lib/action_view/helpers/asset_tag_helper.rb +241 -82
  15. data/lib/action_view/helpers/asset_url_helper.rb +171 -67
  16. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  17. data/lib/action_view/helpers/cache_helper.rb +112 -42
  18. data/lib/action_view/helpers/capture_helper.rb +20 -13
  19. data/lib/action_view/helpers/controller_helper.rb +15 -4
  20. data/lib/action_view/helpers/csp_helper.rb +26 -0
  21. data/lib/action_view/helpers/csrf_helper.rb +8 -6
  22. data/lib/action_view/helpers/date_helper.rb +230 -129
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +755 -129
  25. data/lib/action_view/helpers/form_options_helper.rb +130 -75
  26. data/lib/action_view/helpers/form_tag_helper.rb +116 -71
  27. data/lib/action_view/helpers/javascript_helper.rb +30 -14
  28. data/lib/action_view/helpers/number_helper.rb +84 -59
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +11 -8
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +232 -75
  33. data/lib/action_view/helpers/tags/base.rb +138 -98
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -19
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +4 -3
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -1
  42. data/lib/action_view/helpers/tags/date_select.rb +37 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +3 -2
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -1
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -6
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +14 -9
  58. data/lib/action_view/helpers/tags/select.rb +11 -10
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +4 -2
  61. data/lib/action_view/helpers/tags/text_field.rb +8 -8
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -1
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +15 -16
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -1
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +56 -38
  70. data/lib/action_view/helpers/translation_helper.rb +91 -47
  71. data/lib/action_view/helpers/url_helper.rb +160 -105
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +65 -61
  74. data/lib/action_view/log_subscriber.rb +61 -10
  75. data/lib/action_view/lookup_context.rb +147 -89
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +28 -23
  78. data/lib/action_view/railtie.rb +62 -6
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +71 -13
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +239 -225
  83. data/lib/action_view/renderer/renderer.rb +22 -8
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
  85. data/lib/action_view/renderer/template_renderer.rb +79 -73
  86. data/lib/action_view/rendering.rb +68 -44
  87. data/lib/action_view/routing_url_for.rb +33 -22
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +44 -29
  90. data/lib/action_view/template/handlers/builder.rb +12 -13
  91. data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
  92. data/lib/action_view/template/handlers/erb.rb +24 -86
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +4 -4
  95. data/lib/action_view/template/handlers.rb +38 -8
  96. data/lib/action_view/template/html.rb +19 -10
  97. data/lib/action_view/template/inline.rb +22 -0
  98. data/lib/action_view/template/raw_file.rb +28 -0
  99. data/lib/action_view/template/resolver.rb +217 -193
  100. data/lib/action_view/template/sources/file.rb +17 -0
  101. data/lib/action_view/template/sources.rb +13 -0
  102. data/lib/action_view/template/text.rb +11 -10
  103. data/lib/action_view/template/types.rb +18 -18
  104. data/lib/action_view/template.rb +146 -90
  105. data/lib/action_view/test_case.rb +52 -32
  106. data/lib/action_view/testing/resolvers.rb +46 -34
  107. data/lib/action_view/unbound_template.rb +31 -0
  108. data/lib/action_view/version.rb +3 -1
  109. data/lib/action_view/view_paths.rb +48 -31
  110. data/lib/action_view.rb +11 -8
  111. data/lib/assets/compiled/rails-ujs.js +746 -0
  112. metadata +41 -32
  113. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  114. 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 AV and AC.
20
+ # Main render entry point shared by Action View and Action Controller.
19
21
  def render(context, options)
20
- if options.respond_to?(:permitted?) && !options.permitted?
21
- raise ArgumentError, "render parameters are not permitted"
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
- render_partial(context, options)
27
+ render_partial_to_object(context, options)
26
28
  else
27
- render_template(context, options)
29
+ render_template_to_object(context, options)
28
30
  end
29
31
  end
30
32
 
@@ -41,13 +43,25 @@ module ActionView
41
43
  end
42
44
  end
43
45
 
44
- # Direct accessor to template rendering.
46
+ # Direct access to template rendering.
45
47
  def render_template(context, options) #:nodoc:
46
- TemplateRenderer.new(@lookup_context).render(context, options)
48
+ render_template_to_object(context, options).body
47
49
  end
48
50
 
49
51
  # Direct access to partial rendering.
50
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 ||= {}
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:
51
65
  PartialRenderer.new(@lookup_context).render(context, options, block)
52
66
  end
53
67
  end
@@ -1,10 +1,11 @@
1
- require 'fiber'
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
10
  class StreamingTemplateRenderer < TemplateRenderer #:nodoc:
10
11
  # A valid Rack::Body (i.e. it responds to each).
@@ -26,78 +27,77 @@ module ActionView
26
27
  end
27
28
 
28
29
  private
29
-
30
- # This is the same logging logic as in ShowExceptions middleware.
31
- # TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron.
32
- def log_error(exception) #:nodoc:
33
- logger = ActionView::Base.logger
34
- return unless logger
35
-
36
- message = "\n#{exception.class} (#{exception.message}):\n"
37
- message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
38
- message << " " << exception.backtrace.join("\n ")
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 = {}) #:nodoc:
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, @view, locals)
52
+ delayed_render(buffer, template, layout, view, locals)
54
53
  end
55
54
  end
56
55
 
57
56
  private
58
-
59
- def delayed_render(buffer, template, layout, view, locals)
60
- # Wrap the given buffer in the StreamingBuffer and pass it to the
61
- # underlying template handler. Now, every time something is concatenated
62
- # to the buffer, it is not appended to an array, but streamed straight
63
- # to the client.
64
- output = ActionView::StreamingBuffer.new(buffer)
65
- yielder = lambda { |*name| view._layout_for(*name) }
66
-
67
- instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
68
- fiber = Fiber.new do
69
- if layout
70
- layout.render(view, locals, output, &yielder)
71
- else
72
- # If you don't have a layout, just render the thing
73
- # and concatenate the final result. This is the same
74
- # as a layout with just <%= yield %>
75
- output.safe_concat view._layout_for
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
+ instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do
66
+ outer_config = I18n.config
67
+ fiber = Fiber.new do
68
+ I18n.config = outer_config
69
+ if layout
70
+ layout.render(view, locals, output, &yielder)
71
+ else
72
+ # If you don't have a layout, just render the thing
73
+ # and concatenate the final result. This is the same
74
+ # as a layout with just <%= yield %>
75
+ output.safe_concat view._layout_for
76
+ end
76
77
  end
77
- end
78
78
 
79
- # Set the view flow to support streaming. It will be aware
80
- # when to stop rendering the layout because it needs to search
81
- # something in the template and vice-versa.
82
- view.view_flow = StreamingFlow.new(view, fiber)
79
+ # Set the view flow to support streaming. It will be aware
80
+ # when to stop rendering the layout because it needs to search
81
+ # something in the template and vice-versa.
82
+ view.view_flow = StreamingFlow.new(view, fiber)
83
83
 
84
- # Yo! Start the fiber!
85
- fiber.resume
84
+ # Yo! Start the fiber!
85
+ fiber.resume
86
86
 
87
- # If the fiber is still alive, it means we need something
88
- # from the template, so start rendering it. If not, it means
89
- # the layout exited without requiring anything from the template.
90
- if fiber.alive?
91
- content = template.render(view, locals, &yielder)
87
+ # If the fiber is still alive, it means we need something
88
+ # from the template, so start rendering it. If not, it means
89
+ # the layout exited without requiring anything from the template.
90
+ if fiber.alive?
91
+ content = template.render(view, locals, &yielder)
92
92
 
93
- # Once rendering the template is done, sets its content in the :layout key.
94
- view.view_flow.set(:layout, content)
93
+ # Once rendering the template is done, sets its content in the :layout key.
94
+ view.view_flow.set(:layout, content)
95
95
 
96
- # In case the layout continues yielding, we need to resume
97
- # the fiber until all yields are handled.
98
- fiber.resume while fiber.alive?
96
+ # In case the layout continues yielding, we need to resume
97
+ # the fiber until all yields are handled.
98
+ fiber.resume while fiber.alive?
99
+ end
99
100
  end
100
101
  end
101
- end
102
102
  end
103
103
  end
@@ -1,101 +1,107 @@
1
- require 'active_support/core_ext/object/try'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/try"
2
4
 
3
5
  module ActionView
4
6
  class TemplateRenderer < AbstractRenderer #:nodoc:
5
7
  def render(context, options)
6
- @view = context
7
8
  @details = extract_details(options)
8
9
  template = determine_template(options)
9
10
 
10
- prepend_formats(template.formats)
11
-
12
- @lookup_context.rendered_format ||= (template.formats.first || formats.first)
11
+ prepend_formats(template.format)
13
12
 
14
- render_template(template, options[:layout], options[:locals])
13
+ render_template(context, template, options[:layout], options[:locals] || {})
15
14
  end
16
15
 
17
16
  private
17
+ # Determine the template to be rendered using the given options.
18
+ def determine_template(options)
19
+ keys = options.has_key?(:locals) ? options[:locals].keys : []
18
20
 
19
- # Determine the template to be rendered using the given options.
20
- def determine_template(options)
21
- keys = options.has_key?(:locals) ? options[:locals].keys : []
22
-
23
- if options.key?(:body)
24
- Template::Text.new(options[:body])
25
- elsif options.key?(:text)
26
- Template::Text.new(options[:text], formats.first)
27
- elsif options.key?(:plain)
28
- Template::Text.new(options[:plain])
29
- elsif options.key?(:html)
30
- Template::HTML.new(options[:html], formats.first)
31
- elsif options.key?(:file)
32
- with_fallbacks { find_file(options[:file], nil, false, keys, @details) }
33
- elsif options.key?(:inline)
34
- handler = Template.handler_for_extension(options[:type] || "erb")
35
- Template.new(options[:inline], "inline template", handler, :locals => keys)
36
- elsif options.key?(:template)
37
- if options[:template].respond_to?(:render)
38
- options[:template]
21
+ if options.key?(:body)
22
+ Template::Text.new(options[:body])
23
+ elsif options.key?(:plain)
24
+ Template::Text.new(options[:plain])
25
+ elsif options.key?(:html)
26
+ Template::HTML.new(options[:html], formats.first)
27
+ elsif options.key?(:file)
28
+ if File.exist?(options[:file])
29
+ Template::RawFile.new(options[:file])
30
+ else
31
+ ActiveSupport::Deprecation.warn "render file: should be given the absolute path to a file"
32
+ @lookup_context.with_fallbacks.find_template(options[:file], nil, false, keys, @details)
33
+ end
34
+ elsif options.key?(:inline)
35
+ handler = Template.handler_for_extension(options[:type] || "erb")
36
+ format = if handler.respond_to?(:default_format)
37
+ handler.default_format
38
+ else
39
+ @lookup_context.formats.first
40
+ end
41
+ Template::Inline.new(options[:inline], "inline template", handler, locals: keys, format: format)
42
+ elsif options.key?(:template)
43
+ if options[:template].respond_to?(:render)
44
+ options[:template]
45
+ else
46
+ @lookup_context.find_template(options[:template], options[:prefixes], false, keys, @details)
47
+ end
39
48
  else
40
- find_template(options[:template], options[:prefixes], false, keys, @details)
49
+ raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file, :plain, :html or :body option."
41
50
  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
51
  end
45
- end
46
-
47
- # Renders the given template. A string representing the layout can be
48
- # supplied as well.
49
- def render_template(template, layout_name = nil, locals = nil) #:nodoc:
50
- view, locals = @view, locals || {}
51
52
 
52
- render_with_layout(layout_name, locals) do |layout|
53
- instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
54
- template.render(view, locals) { |*name| view._layout_for(*name) }
53
+ # Renders the given template. A string representing the layout can be
54
+ # supplied as well.
55
+ def render_template(view, template, layout_name, locals)
56
+ render_with_layout(view, template, layout_name, locals) do |layout|
57
+ instrument(:template, identifier: template.identifier, layout: layout.try(:virtual_path)) do
58
+ template.render(view, locals) { |*name| view._layout_for(*name) }
59
+ end
55
60
  end
56
61
  end
57
- end
58
62
 
59
- def render_with_layout(path, locals) #:nodoc:
60
- layout = path && find_layout(path, locals.keys)
61
- content = yield(layout)
63
+ def render_with_layout(view, template, path, locals)
64
+ layout = path && find_layout(path, locals.keys, [formats.first])
65
+ content = yield(layout)
62
66
 
63
- if layout
64
- view = @view
65
- view.view_flow.set(:layout, content)
66
- layout.render(view, locals){ |*name| view._layout_for(*name) }
67
- else
68
- content
67
+ body = if layout
68
+ view.view_flow.set(:layout, content)
69
+ layout.render(view, locals) { |*name| view._layout_for(*name) }
70
+ else
71
+ content
72
+ end
73
+ build_rendered_template(body, template, layout)
69
74
  end
70
- end
71
75
 
72
- # This is the method which actually finds the layout using details in the lookup
73
- # context object. If no layout is found, it checks if at least a layout with
74
- # the given name exists across all details before raising the error.
75
- def find_layout(layout, keys)
76
- with_layout_format { resolve_layout(layout, keys) }
77
- end
76
+ # This is the method which actually finds the layout using details in the lookup
77
+ # context object. If no layout is found, it checks if at least a layout with
78
+ # the given name exists across all details before raising the error.
79
+ def find_layout(layout, keys, formats)
80
+ resolve_layout(layout, keys, formats)
81
+ end
78
82
 
79
- def resolve_layout(layout, keys)
80
- case layout
81
- when String
82
- begin
83
- if layout =~ /^\//
84
- with_fallbacks { find_template(layout, nil, false, keys, @details) }
85
- else
86
- find_template(layout, nil, false, keys, @details)
83
+ def resolve_layout(layout, keys, formats)
84
+ details = @details.dup
85
+ details[:formats] = formats
86
+
87
+ case layout
88
+ when String
89
+ begin
90
+ if layout.start_with?("/")
91
+ ActiveSupport::Deprecation.warn "Rendering layouts from an absolute path is deprecated."
92
+ @lookup_context.with_fallbacks.find_template(layout, nil, false, [], details)
93
+ else
94
+ @lookup_context.find_template(layout, nil, false, [], details)
95
+ end
96
+ rescue ActionView::MissingTemplate
97
+ all_details = @details.merge(formats: @lookup_context.default_formats)
98
+ raise unless template_exists?(layout, nil, false, [], **all_details)
87
99
  end
88
- rescue ActionView::MissingTemplate
89
- all_details = @details.merge(:formats => @lookup_context.default_formats)
90
- raise unless template_exists?(layout, nil, false, keys, all_details)
100
+ when Proc
101
+ resolve_layout(layout.call(@lookup_context, formats), keys, formats)
102
+ else
103
+ layout
91
104
  end
92
- when Proc
93
- resolve_layout(layout.call, keys)
94
- when FalseClass
95
- nil
96
- else
97
- layout
98
105
  end
99
- end
100
106
  end
101
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,6 +26,13 @@ module ActionView
24
26
  extend ActiveSupport::Concern
25
27
  include ActionView::ViewPaths
26
28
 
29
+ attr_reader :rendered_format
30
+
31
+ def initialize
32
+ @rendered_format = nil
33
+ super
34
+ end
35
+
27
36
  # Overwrite process to setup I18n proxy.
28
37
  def process(*) #:nodoc:
29
38
  old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
@@ -33,48 +42,59 @@ module ActionView
33
42
  end
34
43
 
35
44
  module ClassMethods
36
- def view_context_class
37
- @view_context_class ||= begin
38
- supports_path = supports_path?
39
- routes = respond_to?(:_routes) && _routes
40
- helpers = respond_to?(:_helpers) && _helpers
41
-
42
- Class.new(ActionView::Base) do
43
- if routes
44
- include routes.url_helpers(supports_path)
45
- include routes.mounted_helpers
46
- end
47
-
48
- if helpers
49
- include helpers
50
- end
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
- attr_internal_writer :view_context_class
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
- @_view_context_class ||= self.class.view_context_class
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
- # View.new[lookup_context, assigns, controller]
66
- # Create a new ActionView instance for a controller and we can also pass the arguments.
67
- # View#render(option)
68
- # Returns String with the rendered template
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(view_renderer, view_assigns, self)
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
- # :api: private
77
- def view_renderer
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
- # :api: private
94
- def _render_template(options) #:nodoc:
95
- variant = options[:variant]
108
+ def _render_template(options)
109
+ variant = options.delete(:variant)
110
+ assigns = options.delete(:assigns)
111
+ context = view_context
96
112
 
97
- lookup_context.rendered_format = nil if options[:formats]
113
+ context.assign assigns if assigns
98
114
  lookup_context.variants = variant if variant
99
115
 
100
- view_renderer.render(view_context, options)
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 lookup context.
104
- def _process_format(format, options = {}) #:nodoc:
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
- # :api: private
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,17 @@ module ActionView
121
142
  key = action.include?(?/) ? :template : :action
122
143
  options[key] = action
123
144
  else
124
- options[:partial] = action
145
+ if action.respond_to?(:permitted?) && action.permitted?
146
+ options = action
147
+ else
148
+ options[:partial] = action
149
+ end
125
150
  end
126
151
 
127
152
  options
128
153
  end
129
154
 
130
155
  # Normalize options.
131
- # :api: private
132
156
  def _normalize_options(options)
133
157
  options = super(options)
134
158
  if options[:partial] == true
@@ -1,8 +1,9 @@
1
- require 'action_dispatch/routing/polymorphic_routes'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/routing/polymorphic_routes"
2
4
 
3
5
  module ActionView
4
6
  module RoutingUrlFor
5
-
6
7
  # Returns the URL for the set of +options+ provided. This takes the
7
8
  # same options as +url_for+ in Action Controller (see the
8
9
  # documentation for <tt>ActionController::Base#url_for</tt>). Note that by default
@@ -32,7 +33,7 @@ module ActionView
32
33
  #
33
34
  # ==== Examples
34
35
  # <%= url_for(action: 'index') %>
35
- # # => /blog/
36
+ # # => /blogs/
36
37
  #
37
38
  # <%= url_for(action: 'find', controller: 'books') %>
38
39
  # # => /books/find
@@ -83,23 +84,24 @@ module ActionView
83
84
  super(only_path: _generate_paths_by_default)
84
85
  when Hash
85
86
  options = options.symbolize_keys
86
- unless options.key?(:only_path)
87
- if options[:host].nil?
88
- options[:only_path] = _generate_paths_by_default
89
- else
90
- options[:only_path] = false
91
- end
92
- end
87
+ ensure_only_path_option(options)
88
+
89
+ super(options)
90
+ when ActionController::Parameters
91
+ ensure_only_path_option(options)
93
92
 
94
93
  super(options)
95
94
  when :back
96
95
  _back_url
97
96
  when Array
98
97
  components = options.dup
99
- if _generate_paths_by_default
100
- polymorphic_path(components, components.extract_options!)
98
+ options = components.extract_options!
99
+ ensure_only_path_option(options)
100
+
101
+ if options[:only_path]
102
+ polymorphic_path(components, options)
101
103
  else
102
- polymorphic_url(components, components.extract_options!)
104
+ polymorphic_url(components, options)
103
105
  end
104
106
  else
105
107
  method = _generate_paths_by_default ? :path : :url
@@ -121,15 +123,24 @@ module ActionView
121
123
  controller.url_options
122
124
  end
123
125
 
124
- def _routes_context #:nodoc:
125
- controller
126
- end
127
- protected :_routes_context
126
+ private
127
+ def _routes_context
128
+ controller
129
+ end
128
130
 
129
- def optimize_routes_generation? #:nodoc:
130
- controller.respond_to?(:optimize_routes_generation?, true) ?
131
- controller.optimize_routes_generation? : super
132
- end
133
- protected :optimize_routes_generation?
131
+ def optimize_routes_generation?
132
+ controller.respond_to?(:optimize_routes_generation?, true) ?
133
+ controller.optimize_routes_generation? : super
134
+ end
135
+
136
+ def _generate_paths_by_default
137
+ true
138
+ end
139
+
140
+ def ensure_only_path_option(options)
141
+ unless options.key?(:only_path)
142
+ options[:only_path] = _generate_paths_by_default unless options[:host]
143
+ end
144
+ end
134
145
  end
135
146
  end