actionview 4.2.11.3 → 5.2.7.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.

Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +115 -245
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -6
  5. data/lib/action_view/base.rb +38 -28
  6. data/lib/action_view/buffers.rb +3 -1
  7. data/lib/action_view/context.rb +3 -3
  8. data/lib/action_view/dependency_tracker.rb +54 -20
  9. data/lib/action_view/digestor.rb +94 -83
  10. data/lib/action_view/flows.rb +11 -11
  11. data/lib/action_view/gem_version.rb +5 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +17 -11
  13. data/lib/action_view/helpers/asset_tag_helper.rb +244 -62
  14. data/lib/action_view/helpers/asset_url_helper.rb +170 -67
  15. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  16. data/lib/action_view/helpers/cache_helper.rb +105 -42
  17. data/lib/action_view/helpers/capture_helper.rb +16 -13
  18. data/lib/action_view/helpers/controller_helper.rb +15 -4
  19. data/lib/action_view/helpers/csp_helper.rb +24 -0
  20. data/lib/action_view/helpers/csrf_helper.rb +7 -5
  21. data/lib/action_view/helpers/date_helper.rb +170 -112
  22. data/lib/action_view/helpers/debug_helper.rb +7 -6
  23. data/lib/action_view/helpers/form_helper.rb +521 -127
  24. data/lib/action_view/helpers/form_options_helper.rb +109 -63
  25. data/lib/action_view/helpers/form_tag_helper.rb +110 -67
  26. data/lib/action_view/helpers/javascript_helper.rb +27 -12
  27. data/lib/action_view/helpers/number_helper.rb +77 -58
  28. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  29. data/lib/action_view/helpers/record_tag_helper.rb +14 -99
  30. data/lib/action_view/helpers/rendering_helper.rb +6 -5
  31. data/lib/action_view/helpers/sanitize_helper.rb +20 -15
  32. data/lib/action_view/helpers/tag_helper.rb +229 -73
  33. data/lib/action_view/helpers/tags/base.rb +134 -97
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -18
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -33
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +70 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -11
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +3 -1
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -0
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -2
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -0
  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 -1
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -0
  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 -5
  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 -9
  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 -7
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -0
  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 +17 -13
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -0
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +55 -36
  70. data/lib/action_view/helpers/translation_helper.rb +74 -32
  71. data/lib/action_view/helpers/url_helper.rb +159 -104
  72. data/lib/action_view/helpers.rb +5 -1
  73. data/lib/action_view/layouts.rb +65 -58
  74. data/lib/action_view/log_subscriber.rb +60 -8
  75. data/lib/action_view/lookup_context.rb +80 -65
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +30 -19
  78. data/lib/action_view/railtie.rb +39 -6
  79. data/lib/action_view/record_identifier.rb +53 -25
  80. data/lib/action_view/renderer/abstract_renderer.rb +21 -15
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +57 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +218 -214
  83. data/lib/action_view/renderer/renderer.rb +8 -6
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +50 -48
  85. data/lib/action_view/renderer/template_renderer.rb +67 -66
  86. data/lib/action_view/rendering.rb +19 -14
  87. data/lib/action_view/routing_url_for.rb +27 -17
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +16 -16
  90. data/lib/action_view/template/handlers/builder.rb +10 -11
  91. data/lib/action_view/template/handlers/erb/erubi.rb +83 -0
  92. data/lib/action_view/template/handlers/erb.rb +9 -80
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +3 -3
  95. data/lib/action_view/template/handlers.rb +11 -7
  96. data/lib/action_view/template/html.rb +5 -5
  97. data/lib/action_view/template/resolver.rb +140 -115
  98. data/lib/action_view/template/text.rb +8 -9
  99. data/lib/action_view/template/types.rb +18 -18
  100. data/lib/action_view/template.rb +54 -33
  101. data/lib/action_view/test_case.rb +50 -29
  102. data/lib/action_view/testing/resolvers.rb +31 -31
  103. data/lib/action_view/version.rb +3 -1
  104. data/lib/action_view/view_paths.rb +28 -34
  105. data/lib/action_view.rb +8 -7
  106. data/lib/assets/compiled/rails-ujs.js +720 -0
  107. metadata +28 -27
  108. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "action_view"
2
4
  require "rails"
3
5
 
4
6
  module ActionView
5
7
  # = Action View Railtie
6
- class Railtie < Rails::Railtie # :nodoc:
8
+ class Railtie < Rails::Engine # :nodoc:
7
9
  config.action_view = ActiveSupport::OrderedOptions.new
8
- config.action_view.embed_authenticity_token_in_remote_forms = false
10
+ config.action_view.embed_authenticity_token_in_remote_forms = nil
11
+ config.action_view.debug_missing_translation = true
9
12
 
10
13
  config.eager_load_namespaces << ActionView
11
14
 
@@ -16,13 +19,29 @@ module ActionView
16
19
  end
17
20
  end
18
21
 
22
+ initializer "action_view.form_with_generates_remote_forms" do |app|
23
+ ActiveSupport.on_load(:action_view) do
24
+ form_with_generates_remote_forms = app.config.action_view.delete(:form_with_generates_remote_forms)
25
+ ActionView::Helpers::FormHelper.form_with_generates_remote_forms = form_with_generates_remote_forms
26
+ end
27
+ end
28
+
29
+ initializer "action_view.form_with_generates_ids" do |app|
30
+ ActiveSupport.on_load(:action_view) do
31
+ form_with_generates_ids = app.config.action_view.delete(:form_with_generates_ids)
32
+ unless form_with_generates_ids.nil?
33
+ ActionView::Helpers::FormHelper.form_with_generates_ids = form_with_generates_ids
34
+ end
35
+ end
36
+ end
37
+
19
38
  initializer "action_view.logger" do
20
39
  ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger }
21
40
  end
22
41
 
23
42
  initializer "action_view.set_configs" do |app|
24
43
  ActiveSupport.on_load(:action_view) do
25
- app.config.action_view.each do |k,v|
44
+ app.config.action_view.each do |k, v|
26
45
  send "#{k}=", v
27
46
  end
28
47
  end
@@ -36,14 +55,28 @@ module ActionView
36
55
  end
37
56
  end
38
57
 
58
+ initializer "action_view.per_request_digest_cache" do |app|
59
+ ActiveSupport.on_load(:action_view) do
60
+ unless ActionView::Resolver.caching?
61
+ app.executor.to_run ActionView::Digestor::PerExecutionDigestCacheExpiry
62
+ end
63
+ end
64
+ end
65
+
39
66
  initializer "action_view.setup_action_pack" do |app|
40
67
  ActiveSupport.on_load(:action_controller) do
41
- ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
68
+ ActionView::RoutingUrlFor.include(ActionDispatch::Routing::UrlFor)
42
69
  end
43
70
  end
44
71
 
45
- rake_tasks do
46
- load "action_view/tasks/dependencies.rake"
72
+ initializer "action_view.collection_caching", after: "action_controller.set_configs" do |app|
73
+ PartialRenderer.collection_cache = app.config.action_controller.cache_store
74
+ end
75
+
76
+ rake_tasks do |app|
77
+ unless app.config.api_only
78
+ load "action_view/tasks/cache_digests.rake"
79
+ end
47
80
  end
48
81
  end
49
82
  end
@@ -1,38 +1,66 @@
1
- require 'active_support/core_ext/module'
2
- require 'action_view/model_naming'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module"
4
+ require "action_view/model_naming"
3
5
 
4
6
  module ActionView
5
- # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
6
- # pretty much any other model type that has an id. These patterns are then used to try elevate the view actions to
7
- # a higher logical level.
7
+ # RecordIdentifier encapsulates methods used by various ActionView helpers
8
+ # to associate records with DOM elements.
8
9
  #
9
- # # routes
10
- # resources :posts
10
+ # Consider for example the following code that form of post:
11
11
  #
12
- # # view
13
- # <%= div_for(post) do %> <div id="post_45" class="post">
14
- # <%= post.body %> What a wonderful world!
15
- # <% end %> </div>
12
+ # <%= form_for(post) do |f| %>
13
+ # <%= f.text_field :body %>
14
+ # <% end %>
16
15
  #
17
- # # controller
18
- # def update
19
- # post = Post.find(params[:id])
20
- # post.update(params[:post])
16
+ # When +post+ is a new, unsaved ActiveRecord::Base instance, the resulting HTML
17
+ # is:
21
18
  #
22
- # redirect_to(post) # Calls polymorphic_url(post) which in turn calls post_url(post)
23
- # end
19
+ # <form class="new_post" id="new_post" action="/posts" accept-charset="UTF-8" method="post">
20
+ # <input type="text" name="post[body]" id="post_body" />
21
+ # </form>
22
+ #
23
+ # When +post+ is a persisted ActiveRecord::Base instance, the resulting HTML
24
+ # is:
25
+ #
26
+ # <form class="edit_post" id="edit_post_42" action="/posts/42" accept-charset="UTF-8" method="post">
27
+ # <input type="text" value="What a wonderful world!" name="post[body]" id="post_body" />
28
+ # </form>
29
+ #
30
+ # In both cases, the +id+ and +class+ of the wrapping DOM element are
31
+ # automatically generated, following naming conventions encapsulated by the
32
+ # RecordIdentifier methods #dom_id and #dom_class:
24
33
  #
25
- # As the example above shows, you can stop caring to a large extent what the actual id of the post is.
26
- # You just know that one is being assigned and that the subsequent calls in redirect_to expect that
27
- # same naming convention and allows you to write less code if you follow it.
34
+ # dom_id(Post.new) # => "new_post"
35
+ # dom_class(Post.new) # => "post"
36
+ # dom_id(Post.find 42) # => "post_42"
37
+ # dom_class(Post.find 42) # => "post"
38
+ #
39
+ # Note that these methods do not strictly require +Post+ to be a subclass of
40
+ # ActiveRecord::Base.
41
+ # Any +Post+ class will work as long as its instances respond to +to_key+
42
+ # and +model_name+, given that +model_name+ responds to +param_key+.
43
+ # For instance:
44
+ #
45
+ # class Post
46
+ # attr_accessor :to_key
47
+ #
48
+ # def model_name
49
+ # OpenStruct.new param_key: 'post'
50
+ # end
51
+ #
52
+ # def self.find(id)
53
+ # new.tap { |post| post.to_key = [id] }
54
+ # end
55
+ # end
28
56
  module RecordIdentifier
29
57
  extend self
30
58
  extend ModelNaming
31
59
 
32
60
  include ModelNaming
33
61
 
34
- JOIN = '_'.freeze
35
- NEW = 'new'.freeze
62
+ JOIN = "_".freeze
63
+ NEW = "new".freeze
36
64
 
37
65
  # The DOM class convention is to use the singular form of an object or class.
38
66
  #
@@ -66,7 +94,7 @@ module ActionView
66
94
  end
67
95
  end
68
96
 
69
- protected
97
+ private
70
98
 
71
99
  # Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
72
100
  # This can be overwritten to customize the default generated string representation if desired.
@@ -76,9 +104,9 @@ module ActionView
76
104
  # overwritten version of the method. By default, this implementation passes the key string through a
77
105
  # method that replaces all characters that are invalid inside DOM ids, with valid ones. You need to
78
106
  # make sure yourself that your dom ids are valid, in case you overwrite this method.
79
- def record_key_for_dom_id(record)
107
+ def record_key_for_dom_id(record) # :doc:
80
108
  key = convert_to_model(record).to_key
81
- key ? key.join('_') : key
109
+ key ? key.join(JOIN) : key
82
110
  end
83
111
  end
84
112
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
4
  # This class defines the interface for a renderer. Each class that
3
5
  # subclasses +AbstractRenderer+ is used by the base +Renderer+ class to
@@ -15,7 +17,7 @@ module ActionView
15
17
  # that new object is called in turn. This abstracts the setup and rendering
16
18
  # into a separate classes for partials and templates.
17
19
  class AbstractRenderer #:nodoc:
18
- delegate :find_template, :find_file, :template_exists?, :with_fallbacks, :with_layout_format, :formats, :to => :@lookup_context
20
+ delegate :find_template, :find_file, :template_exists?, :any_templates?, :with_fallbacks, :with_layout_format, :formats, to: :@lookup_context
19
21
 
20
22
  def initialize(lookup_context)
21
23
  @lookup_context = lookup_context
@@ -25,25 +27,29 @@ module ActionView
25
27
  raise NotImplementedError
26
28
  end
27
29
 
28
- protected
30
+ private
29
31
 
30
- def extract_details(options)
31
- @lookup_context.registered_details.each_with_object({}) do |key, details|
32
- value = options[key]
32
+ def extract_details(options) # :doc:
33
+ @lookup_context.registered_details.each_with_object({}) do |key, details|
34
+ value = options[key]
33
35
 
34
- details[key] = Array(value) if value
36
+ details[key] = Array(value) if value
37
+ end
35
38
  end
36
- end
37
39
 
38
- def instrument(name, options={})
39
- ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield }
40
- end
40
+ def instrument(name, **options) # :doc:
41
+ options[:identifier] ||= (@template && @template.identifier) || @path
41
42
 
42
- def prepend_formats(formats)
43
- formats = Array(formats)
44
- return if formats.empty? || @lookup_context.html_fallback_for_js
43
+ ActiveSupport::Notifications.instrument("render_#{name}.action_view", options) do |payload|
44
+ yield payload
45
+ end
46
+ end
45
47
 
46
- @lookup_context.formats = formats | @lookup_context.formats
47
- end
48
+ def prepend_formats(formats) # :doc:
49
+ formats = Array(formats)
50
+ return if formats.empty? || @lookup_context.html_fallback_for_js
51
+
52
+ @lookup_context.formats = formats | @lookup_context.formats
53
+ end
48
54
  end
49
55
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView
4
+ module CollectionCaching # :nodoc:
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ # Fallback cache store if Action View is used without Rails.
9
+ # Otherwise overridden in Railtie to use Rails.cache.
10
+ mattr_accessor :collection_cache, default: ActiveSupport::Cache::MemoryStore.new
11
+ end
12
+
13
+ private
14
+ def cache_collection_render(instrumentation_payload)
15
+ return yield unless @options[:cached]
16
+
17
+ keyed_collection = collection_by_cache_keys
18
+ cached_partials = collection_cache.read_multi(*keyed_collection.keys)
19
+ instrumentation_payload[:cache_hits] = cached_partials.size
20
+
21
+ @collection = keyed_collection.reject { |key, _| cached_partials.key?(key) }.values
22
+ rendered_partials = @collection.empty? ? [] : yield
23
+
24
+ index = 0
25
+ fetch_or_cache_partial(cached_partials, order_by: keyed_collection.each_key) do
26
+ rendered_partials[index].tap { index += 1 }
27
+ end
28
+ end
29
+
30
+ def callable_cache_key?
31
+ @options[:cached].respond_to?(:call)
32
+ end
33
+
34
+ def collection_by_cache_keys
35
+ seed = callable_cache_key? ? @options[:cached] : ->(i) { i }
36
+
37
+ @collection.each_with_object({}) do |item, hash|
38
+ hash[expanded_cache_key(seed.call(item))] = item
39
+ end
40
+ end
41
+
42
+ def expanded_cache_key(key)
43
+ key = @view.combined_fragment_cache_key(@view.cache_fragment_name(key, virtual_path: @template.virtual_path))
44
+ key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
45
+ end
46
+
47
+ def fetch_or_cache_partial(cached_partials, order_by:)
48
+ order_by.map do |cache_key|
49
+ cached_partials.fetch(cache_key) do
50
+ yield.tap do |rendered_partial|
51
+ collection_cache.write(cache_key, rendered_partial)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end