actionview 4.2.11.1 → 6.1.5

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +232 -186
  3. data/MIT-LICENSE +1 -2
  4. data/README.rdoc +9 -8
  5. data/lib/action_view/base.rb +115 -39
  6. data/lib/action_view/buffers.rb +18 -1
  7. data/lib/action_view/cache_expiry.rb +52 -0
  8. data/lib/action_view/context.rb +8 -12
  9. data/lib/action_view/dependency_tracker.rb +61 -21
  10. data/lib/action_view/digestor.rb +89 -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 +282 -83
  15. data/lib/action_view/helpers/asset_url_helper.rb +175 -69
  16. data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
  17. data/lib/action_view/helpers/cache_helper.rb +107 -43
  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 +232 -130
  23. data/lib/action_view/helpers/debug_helper.rb +7 -6
  24. data/lib/action_view/helpers/form_helper.rb +808 -146
  25. data/lib/action_view/helpers/form_options_helper.rb +124 -78
  26. data/lib/action_view/helpers/form_tag_helper.rb +120 -74
  27. data/lib/action_view/helpers/javascript_helper.rb +33 -17
  28. data/lib/action_view/helpers/number_helper.rb +87 -62
  29. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  30. data/lib/action_view/helpers/rendering_helper.rb +21 -10
  31. data/lib/action_view/helpers/sanitize_helper.rb +30 -31
  32. data/lib/action_view/helpers/tag_helper.rb +269 -68
  33. data/lib/action_view/helpers/tags/base.rb +141 -97
  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 +3 -2
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -37
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
  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 +6 -0
  50. data/lib/action_view/helpers/tags/label.rb +7 -2
  51. data/lib/action_view/helpers/tags/month_field.rb +3 -2
  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 +3 -2
  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 +3 -2
  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 +150 -68
  71. data/lib/action_view/helpers/url_helper.rb +284 -117
  72. data/lib/action_view/helpers.rb +5 -3
  73. data/lib/action_view/layouts.rb +68 -63
  74. data/lib/action_view/log_subscriber.rb +77 -10
  75. data/lib/action_view/lookup_context.rb +134 -91
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +26 -24
  78. data/lib/action_view/railtie.rb +62 -13
  79. data/lib/action_view/record_identifier.rb +53 -26
  80. data/lib/action_view/renderer/abstract_renderer.rb +151 -14
  81. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  82. data/lib/action_view/renderer/object_renderer.rb +34 -0
  83. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
  84. data/lib/action_view/renderer/partial_renderer.rb +55 -303
  85. data/lib/action_view/renderer/renderer.rb +66 -9
  86. data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
  87. data/lib/action_view/renderer/template_renderer.rb +82 -73
  88. data/lib/action_view/rendering.rb +71 -45
  89. data/lib/action_view/routing_url_for.rb +34 -23
  90. data/lib/action_view/tasks/cache_digests.rake +25 -0
  91. data/lib/action_view/template/error.rb +44 -29
  92. data/lib/action_view/template/handlers/builder.rb +12 -13
  93. data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
  94. data/lib/action_view/template/handlers/erb.rb +23 -89
  95. data/lib/action_view/template/handlers/html.rb +11 -0
  96. data/lib/action_view/template/handlers/raw.rb +4 -4
  97. data/lib/action_view/template/handlers.rb +12 -8
  98. data/lib/action_view/template/html.rb +10 -11
  99. data/lib/action_view/template/inline.rb +22 -0
  100. data/lib/action_view/template/raw_file.rb +25 -0
  101. data/lib/action_view/template/renderable.rb +24 -0
  102. data/lib/action_view/template/resolver.rb +263 -197
  103. data/lib/action_view/template/sources/file.rb +17 -0
  104. data/lib/action_view/template/sources.rb +13 -0
  105. data/lib/action_view/template/text.rb +8 -10
  106. data/lib/action_view/template/types.rb +18 -18
  107. data/lib/action_view/template.rb +108 -92
  108. data/lib/action_view/test_case.rb +66 -53
  109. data/lib/action_view/testing/resolvers.rb +24 -33
  110. data/lib/action_view/unbound_template.rb +31 -0
  111. data/lib/action_view/version.rb +3 -1
  112. data/lib/action_view/view_paths.rb +73 -58
  113. data/lib/action_view.rb +14 -8
  114. data/lib/assets/compiled/rails-ujs.js +746 -0
  115. metadata +42 -29
  116. data/lib/action_view/helpers/record_tag_helper.rb +0 -108
  117. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,48 +1,44 @@
1
- require 'thread_safe'
2
- require 'active_support/core_ext/module/remove_method'
3
- require 'active_support/core_ext/module/attribute_accessors'
4
- require 'action_view/template/resolver'
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+ require "active_support/core_ext/module/attribute_accessors"
5
+ require "action_view/template/resolver"
5
6
 
6
7
  module ActionView
7
8
  # = Action View Lookup Context
8
9
  #
9
- # LookupContext is the object responsible to hold all information required to lookup
10
- # templates, i.e. view paths and details. The LookupContext is also responsible to
11
- # generate a key, given to view paths, used in the resolver cache lookup. Since
12
- # this key is generated just once during the request, it speeds up all cache accesses.
10
+ # <tt>LookupContext</tt> is the object responsible for holding all information
11
+ # required for looking up templates, i.e. view paths and details.
12
+ # <tt>LookupContext</tt> is also responsible for generating a key, given to
13
+ # view paths, used in the resolver cache lookup. Since this key is generated
14
+ # only once during the request, it speeds up all cache accesses.
13
15
  class LookupContext #:nodoc:
14
16
  attr_accessor :prefixes, :rendered_format
15
17
 
16
- mattr_accessor :fallbacks
17
- @@fallbacks = FallbackFileSystemResolver.instances
18
+ mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
18
19
 
19
- mattr_accessor :registered_details
20
- self.registered_details = []
20
+ mattr_accessor :registered_details, default: []
21
21
 
22
- def self.register_detail(name, options = {}, &block)
23
- self.registered_details << name
24
- initialize = registered_details.map { |n| "@details[:#{n}] = details[:#{n}] || default_#{n}" }
22
+ def self.register_detail(name, &block)
23
+ registered_details << name
24
+ Accessors::DEFAULT_PROCS[name] = block
25
25
 
26
- Accessors.send :define_method, :"default_#{name}", &block
26
+ Accessors.define_method(:"default_#{name}", &block)
27
27
  Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
28
28
  def #{name}
29
- @details.fetch(:#{name}, [])
29
+ @details[:#{name}] || []
30
30
  end
31
31
 
32
32
  def #{name}=(value)
33
33
  value = value.present? ? Array(value) : default_#{name}
34
34
  _set_detail(:#{name}, value) if value != @details[:#{name}]
35
35
  end
36
-
37
- remove_possible_method :initialize_details
38
- def initialize_details(details)
39
- #{initialize.join("\n")}
40
- end
41
36
  METHOD
42
37
  end
43
38
 
44
39
  # Holds accessors for the registered details.
45
40
  module Accessors #:nodoc:
41
+ DEFAULT_PROCS = {}
46
42
  end
47
43
 
48
44
  register_detail(:locale) do
@@ -54,29 +50,45 @@ module ActionView
54
50
  end
55
51
  register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] }
56
52
  register_detail(:variants) { [] }
57
- register_detail(:handlers){ Template::Handlers.extensions }
53
+ register_detail(:handlers) { Template::Handlers.extensions }
58
54
 
59
55
  class DetailsKey #:nodoc:
60
56
  alias :eql? :equal?
61
- alias :object_hash :hash
62
57
 
63
- attr_reader :hash
64
- @details_keys = ThreadSafe::Cache.new
58
+ @details_keys = Concurrent::Map.new
59
+ @digest_cache = Concurrent::Map.new
60
+ @view_context_mutex = Mutex.new
65
61
 
66
- def self.get(details)
62
+ def self.digest_cache(details)
63
+ @digest_cache[details_cache_key(details)] ||= Concurrent::Map.new
64
+ end
65
+
66
+ def self.details_cache_key(details)
67
67
  if details[:formats]
68
68
  details = details.dup
69
- details[:formats] &= Mime::SET.symbols
69
+ details[:formats] &= Template::Types.symbols
70
70
  end
71
- @details_keys[details] ||= new
71
+ @details_keys[details] ||= Object.new
72
72
  end
73
73
 
74
74
  def self.clear
75
+ ActionView::ViewPaths.all_view_paths.each do |path_set|
76
+ path_set.each(&:clear_cache)
77
+ end
78
+ ActionView::LookupContext.fallbacks.each(&:clear_cache)
79
+ @view_context_class = nil
75
80
  @details_keys.clear
81
+ @digest_cache.clear
76
82
  end
77
83
 
78
- def initialize
79
- @hash = object_hash
84
+ def self.digest_caches
85
+ @digest_cache.values
86
+ end
87
+
88
+ def self.view_context_class(klass)
89
+ @view_context_mutex.synchronize do
90
+ @view_context_class ||= klass.with_empty_template_cache
91
+ end
80
92
  end
81
93
  end
82
94
 
@@ -87,7 +99,7 @@ module ActionView
87
99
  # Calculate the details key. Remove the handlers from calculation to improve performance
88
100
  # since the user cannot modify it explicitly.
89
101
  def details_key #:nodoc:
90
- @details_key ||= DetailsKey.get(@details) if @cache
102
+ @details_key ||= DetailsKey.details_cache_key(@details) if @cache
91
103
  end
92
104
 
93
105
  # Temporary skip passing the details_key forward.
@@ -98,10 +110,10 @@ module ActionView
98
110
  @cache = old_value
99
111
  end
100
112
 
101
- protected
102
-
103
- def _set_detail(key, value)
104
- @details = @details.dup if @details_key
113
+ private
114
+ def _set_detail(key, value) # :doc:
115
+ @details = @details.dup if @digest_cache || @details_key
116
+ @digest_cache = nil
105
117
  @details_key = nil
106
118
  @details[key] = value
107
119
  end
@@ -111,59 +123,60 @@ module ActionView
111
123
  module ViewPaths
112
124
  attr_reader :view_paths, :html_fallback_for_js
113
125
 
114
- # Whenever setting view paths, makes a copy so that we can manipulate them in
115
- # instance objects as we wish.
116
- def view_paths=(paths)
117
- @view_paths = ActionView::PathSet.new(Array(paths))
118
- end
119
-
120
126
  def find(name, prefixes = [], partial = false, keys = [], options = {})
121
127
  @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
122
128
  end
123
129
  alias :find_template :find
124
130
 
125
- def find_file(name, prefixes = [], partial = false, keys = [], options = {})
126
- @view_paths.find_file(*args_for_lookup(name, prefixes, partial, keys, options))
127
- end
128
-
129
131
  def find_all(name, prefixes = [], partial = false, keys = [], options = {})
130
132
  @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
131
133
  end
132
134
 
133
- def exists?(name, prefixes = [], partial = false, keys = [], options = {})
135
+ def exists?(name, prefixes = [], partial = false, keys = [], **options)
134
136
  @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
135
137
  end
136
138
  alias :template_exists? :exists?
137
139
 
140
+ def any?(name, prefixes = [], partial = false)
141
+ @view_paths.exists?(*args_for_any(name, prefixes, partial))
142
+ end
143
+ alias :any_templates? :any?
144
+
138
145
  # Adds fallbacks to the view paths. Useful in cases when you are rendering
139
146
  # a :file.
140
147
  def with_fallbacks
141
- added_resolvers = 0
142
- self.class.fallbacks.each do |resolver|
143
- next if view_paths.include?(resolver)
144
- view_paths.push(resolver)
145
- added_resolvers += 1
148
+ view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
149
+
150
+ if block_given?
151
+ raise ArgumentError, <<~eowarn.squish
152
+ Calling `with_fallbacks` with a block is not supported. Call methods on
153
+ the lookup context returned by `with_fallbacks` instead.
154
+ eowarn
155
+ else
156
+ ActionView::LookupContext.new(view_paths, @details, @prefixes)
146
157
  end
147
- yield
148
- ensure
149
- added_resolvers.times { view_paths.pop }
150
158
  end
151
159
 
152
- protected
160
+ private
161
+ # Whenever setting view paths, makes a copy so that we can manipulate them in
162
+ # instance objects as we wish.
163
+ def build_view_paths(paths)
164
+ ActionView::PathSet.new(Array(paths))
165
+ end
153
166
 
154
- def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
167
+ def args_for_lookup(name, prefixes, partial, keys, details_options)
155
168
  name, prefixes = normalize_name(name, prefixes)
156
169
  details, details_key = detail_args_for(details_options)
157
170
  [name, prefixes, partial || false, details, details_key, keys]
158
171
  end
159
172
 
160
173
  # Compute details hash and key according to user options (e.g. passed from #render).
161
- def detail_args_for(options)
174
+ def detail_args_for(options) # :doc:
162
175
  return @details, details_key if options.empty? # most common path.
163
176
  user_details = @details.merge(options)
164
177
 
165
178
  if @cache
166
- details_key = DetailsKey.get(user_details)
179
+ details_key = DetailsKey.details_cache_key(user_details)
167
180
  else
168
181
  details_key = nil
169
182
  end
@@ -171,18 +184,44 @@ module ActionView
171
184
  [user_details, details_key]
172
185
  end
173
186
 
187
+ def args_for_any(name, prefixes, partial)
188
+ name, prefixes = normalize_name(name, prefixes)
189
+ details, details_key = detail_args_for_any
190
+ [name, prefixes, partial || false, details, details_key]
191
+ end
192
+
193
+ def detail_args_for_any
194
+ @detail_args_for_any ||= begin
195
+ details = {}
196
+
197
+ registered_details.each do |k|
198
+ if k == :variants
199
+ details[k] = :any
200
+ else
201
+ details[k] = Accessors::DEFAULT_PROCS[k].call
202
+ end
203
+ end
204
+
205
+ if @cache
206
+ [details, DetailsKey.details_cache_key(details)]
207
+ else
208
+ [details, nil]
209
+ end
210
+ end
211
+ end
212
+
174
213
  # Support legacy foo.erb names even though we now ignore .erb
175
214
  # as well as incorrectly putting part of the path in the template
176
215
  # name instead of the prefix.
177
- def normalize_name(name, prefixes) #:nodoc:
216
+ def normalize_name(name, prefixes)
178
217
  prefixes = prefixes.presence
179
- parts = name.to_s.split('/')
218
+ parts = name.to_s.split("/")
180
219
  parts.shift if parts.first.empty?
181
- name = parts.pop
220
+ name = parts.pop
182
221
 
183
222
  return name, prefixes || [""] if parts.empty?
184
223
 
185
- parts = parts.join('/')
224
+ parts = parts.join("/")
186
225
  prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
187
226
 
188
227
  return name, prefixes
@@ -194,21 +233,47 @@ module ActionView
194
233
  include ViewPaths
195
234
 
196
235
  def initialize(view_paths, details = {}, prefixes = [])
197
- @details, @details_key = {}, nil
198
- @skip_default_locale = false
236
+ @details_key = nil
237
+ @digest_cache = nil
199
238
  @cache = true
200
239
  @prefixes = prefixes
201
- @rendered_format = nil
202
240
 
203
- self.view_paths = view_paths
204
- initialize_details(details)
241
+ @details = initialize_details({}, details)
242
+ @view_paths = build_view_paths(view_paths)
243
+ end
244
+
245
+ def digest_cache
246
+ @digest_cache ||= DetailsKey.digest_cache(@details)
247
+ end
248
+
249
+ def with_prepended_formats(formats)
250
+ details = @details.dup
251
+ details[:formats] = formats
252
+
253
+ self.class.new(@view_paths, details, @prefixes)
254
+ end
255
+
256
+ def initialize_details(target, details)
257
+ registered_details.each do |k|
258
+ target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
259
+ end
260
+ target
205
261
  end
262
+ private :initialize_details
206
263
 
207
264
  # Override formats= to expand ["*/*"] values and automatically
208
265
  # add :html as fallback to :js.
209
266
  def formats=(values)
210
267
  if values
268
+ values = values.dup
211
269
  values.concat(default_formats) if values.delete "*/*"
270
+ values.uniq!
271
+
272
+ invalid_values = (values - Template::Types.symbols)
273
+ unless invalid_values.empty?
274
+ raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
275
+ end
276
+
212
277
  if values == [:js]
213
278
  values << :html
214
279
  @html_fallback_for_js = true
@@ -217,12 +282,6 @@ module ActionView
217
282
  super(values)
218
283
  end
219
284
 
220
- # Do not use the default locale on template lookup.
221
- def skip_default_locale!
222
- @skip_default_locale = true
223
- self.locale = nil
224
- end
225
-
226
285
  # Override locale to return a symbol instead of array.
227
286
  def locale
228
287
  @details[:locale].first
@@ -237,23 +296,7 @@ module ActionView
237
296
  config.locale = value
238
297
  end
239
298
 
240
- super(@skip_default_locale ? I18n.locale : default_locale)
241
- end
242
-
243
- # Uses the first format in the formats array for layout lookup.
244
- def with_layout_format
245
- if formats.size == 1
246
- yield
247
- else
248
- old_formats = formats
249
- _set_detail(:formats, formats[0,1])
250
-
251
- begin
252
- yield
253
- ensure
254
- _set_detail(:formats, old_formats)
255
- end
256
- end
299
+ super(default_locale)
257
300
  end
258
301
  end
259
302
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView
2
- module ModelNaming
4
+ module ModelNaming #:nodoc:
3
5
  # Converts the given object to an ActiveModel compliant one.
4
6
  def convert_to_model(object)
5
7
  object.respond_to?(:to_model) ? object.to_model : object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionView #:nodoc:
2
4
  # = Action View PathSet
3
5
  #
@@ -46,44 +48,44 @@ module ActionView #:nodoc:
46
48
  find_all(*args).first || raise(MissingTemplate.new(self, *args))
47
49
  end
48
50
 
49
- def find_file(path, prefixes = [], *args)
50
- _find_all(path, prefixes, args, true).first || raise(MissingTemplate.new(self, path, prefixes, *args))
51
- end
52
-
53
51
  def find_all(path, prefixes = [], *args)
54
- _find_all path, prefixes, args, false
52
+ _find_all path, prefixes, args
55
53
  end
56
54
 
57
55
  def exists?(path, prefixes, *args)
58
56
  find_all(path, prefixes, *args).any?
59
57
  end
60
58
 
61
- private
59
+ def find_all_with_query(query) # :nodoc:
60
+ paths.each do |resolver|
61
+ templates = resolver.find_all_with_query(query)
62
+ return templates unless templates.empty?
63
+ end
62
64
 
63
- def _find_all(path, prefixes, args, outside_app)
64
- prefixes = [prefixes] if String === prefixes
65
- prefixes.each do |prefix|
66
- paths.each do |resolver|
67
- if outside_app
68
- templates = resolver.find_all_anywhere(path, prefix, *args)
69
- else
65
+ []
66
+ end
67
+
68
+ private
69
+ def _find_all(path, prefixes, args)
70
+ prefixes = [prefixes] if String === prefixes
71
+ prefixes.each do |prefix|
72
+ paths.each do |resolver|
70
73
  templates = resolver.find_all(path, prefix, *args)
74
+ return templates unless templates.empty?
71
75
  end
72
- return templates unless templates.empty?
73
76
  end
77
+ []
74
78
  end
75
- []
76
- end
77
79
 
78
- def typecast(paths)
79
- paths.map do |path|
80
- case path
81
- when Pathname, String
82
- OptimizedFileSystemResolver.new path.to_s
83
- else
84
- path
80
+ def typecast(paths)
81
+ paths.map do |path|
82
+ case path
83
+ when Pathname, String
84
+ OptimizedFileSystemResolver.new path.to_s
85
+ else
86
+ path
87
+ end
85
88
  end
86
89
  end
87
- end
88
90
  end
89
91
  end
@@ -1,33 +1,64 @@
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
12
+ config.action_view.default_enforce_utf8 = nil
9
13
 
10
14
  config.eager_load_namespaces << ActionView
11
15
 
12
- initializer "action_view.embed_authenticity_token_in_remote_forms" do |app|
13
- ActiveSupport.on_load(:action_view) do
14
- ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms =
15
- app.config.action_view.delete(:embed_authenticity_token_in_remote_forms)
16
+ config.after_initialize do |app|
17
+ ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms =
18
+ app.config.action_view.delete(:embed_authenticity_token_in_remote_forms)
19
+ end
20
+
21
+ config.after_initialize do |app|
22
+ form_with_generates_remote_forms = app.config.action_view.delete(:form_with_generates_remote_forms)
23
+ ActionView::Helpers::FormHelper.form_with_generates_remote_forms = form_with_generates_remote_forms
24
+ end
25
+
26
+ config.after_initialize do |app|
27
+ form_with_generates_ids = app.config.action_view.delete(:form_with_generates_ids)
28
+ unless form_with_generates_ids.nil?
29
+ ActionView::Helpers::FormHelper.form_with_generates_ids = form_with_generates_ids
16
30
  end
17
31
  end
18
32
 
19
- initializer "action_view.logger" do
20
- ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger }
33
+ config.after_initialize do |app|
34
+ default_enforce_utf8 = app.config.action_view.delete(:default_enforce_utf8)
35
+ unless default_enforce_utf8.nil?
36
+ ActionView::Helpers::FormTagHelper.default_enforce_utf8 = default_enforce_utf8
37
+ end
21
38
  end
22
39
 
23
- initializer "action_view.set_configs" do |app|
40
+ config.after_initialize do |app|
41
+ ActionView::Helpers::AssetTagHelper.preload_links_header = app.config.action_view.delete(:preload_links_header)
42
+ end
43
+
44
+ config.after_initialize do |app|
24
45
  ActiveSupport.on_load(:action_view) do
25
- app.config.action_view.each do |k,v|
46
+ app.config.action_view.each do |k, v|
47
+ if k == :raise_on_missing_translations
48
+ ActiveSupport::Deprecation.warn \
49
+ "action_view.raise_on_missing_translations is deprecated and will be removed in Rails 7.0. " \
50
+ "Set i18n.raise_on_missing_translations instead. " \
51
+ "Note that this new setting also affects how missing translations are handled in controllers."
52
+ end
26
53
  send "#{k}=", v
27
54
  end
28
55
  end
29
56
  end
30
57
 
58
+ initializer "action_view.logger" do
59
+ ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger }
60
+ end
61
+
31
62
  initializer "action_view.caching" do |app|
32
63
  ActiveSupport.on_load(:action_view) do
33
64
  if app.config.action_view.cache_template_loading.nil?
@@ -38,12 +69,30 @@ module ActionView
38
69
 
39
70
  initializer "action_view.setup_action_pack" do |app|
40
71
  ActiveSupport.on_load(:action_controller) do
41
- ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
72
+ ActionView::RoutingUrlFor.include(ActionDispatch::Routing::UrlFor)
42
73
  end
43
74
  end
44
75
 
45
- rake_tasks do
46
- load "action_view/tasks/dependencies.rake"
76
+ initializer "action_view.collection_caching", after: "action_controller.set_configs" do |app|
77
+ PartialRenderer.collection_cache = app.config.action_controller.cache_store
78
+ end
79
+
80
+ config.after_initialize do |app|
81
+ enable_caching = if app.config.action_view.cache_template_loading.nil?
82
+ app.config.cache_classes
83
+ else
84
+ app.config.action_view.cache_template_loading
85
+ end
86
+
87
+ unless enable_caching
88
+ app.executor.to_run ActionView::CacheExpiry::Executor.new(watcher: app.config.file_watcher)
89
+ end
90
+ end
91
+
92
+ rake_tasks do |app|
93
+ unless app.config.api_only
94
+ load "action_view/tasks/cache_digests.rake"
95
+ end
47
96
  end
48
97
  end
49
98
  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:
33
+ #
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"
24
38
  #
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.
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 = "_"
63
+ NEW = "new"
36
64
 
37
65
  # The DOM class convention is to use the singular form of an object or class.
38
66
  #
@@ -66,8 +94,7 @@ module ActionView
66
94
  end
67
95
  end
68
96
 
69
- protected
70
-
97
+ private
71
98
  # Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id.
72
99
  # This can be overwritten to customize the default generated string representation if desired.
73
100
  # If you need to read back a key from a dom_id in order to query for the underlying database record,
@@ -76,9 +103,9 @@ module ActionView
76
103
  # overwritten version of the method. By default, this implementation passes the key string through a
77
104
  # method that replaces all characters that are invalid inside DOM ids, with valid ones. You need to
78
105
  # make sure yourself that your dom ids are valid, in case you overwrite this method.
79
- def record_key_for_dom_id(record)
106
+ def record_key_for_dom_id(record) # :doc:
80
107
  key = convert_to_model(record).to_key
81
- key ? key.join('_') : key
108
+ key ? key.join(JOIN) : key
82
109
  end
83
110
  end
84
111
  end