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,29 +1,33 @@
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/remove_method"
5
+ require "active_support/core_ext/module/attribute_accessors"
6
+ require "active_support/deprecation"
7
+ require "action_view/template/resolver"
5
8
 
6
9
  module ActionView
7
10
  # = Action View Lookup Context
8
11
  #
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.
12
+ # <tt>LookupContext</tt> is the object responsible for holding all information
13
+ # required for looking up templates, i.e. view paths and details.
14
+ # <tt>LookupContext</tt> is also responsible for generating a key, given to
15
+ # view paths, used in the resolver cache lookup. Since this key is generated
16
+ # only once during the request, it speeds up all cache accesses.
13
17
  class LookupContext #:nodoc:
14
18
  attr_accessor :prefixes, :rendered_format
19
+ deprecate :rendered_format
20
+ deprecate :rendered_format=
15
21
 
16
- mattr_accessor :fallbacks
17
- @@fallbacks = FallbackFileSystemResolver.instances
22
+ mattr_accessor :fallbacks, default: FallbackFileSystemResolver.instances
18
23
 
19
- mattr_accessor :registered_details
20
- self.registered_details = []
24
+ mattr_accessor :registered_details, default: []
21
25
 
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}" }
26
+ def self.register_detail(name, &block)
27
+ registered_details << name
28
+ Accessors::DEFAULT_PROCS[name] = block
25
29
 
26
- Accessors.send :define_method, :"default_#{name}", &block
30
+ Accessors.define_method(:"default_#{name}", &block)
27
31
  Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
28
32
  def #{name}
29
33
  @details.fetch(:#{name}, [])
@@ -33,16 +37,12 @@ module ActionView
33
37
  value = value.present? ? Array(value) : default_#{name}
34
38
  _set_detail(:#{name}, value) if value != @details[:#{name}]
35
39
  end
36
-
37
- remove_possible_method :initialize_details
38
- def initialize_details(details)
39
- #{initialize.join("\n")}
40
- end
41
40
  METHOD
42
41
  end
43
42
 
44
43
  # Holds accessors for the registered details.
45
44
  module Accessors #:nodoc:
45
+ DEFAULT_PROCS = {}
46
46
  end
47
47
 
48
48
  register_detail(:locale) do
@@ -54,29 +54,45 @@ module ActionView
54
54
  end
55
55
  register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] }
56
56
  register_detail(:variants) { [] }
57
- register_detail(:handlers){ Template::Handlers.extensions }
57
+ register_detail(:handlers) { Template::Handlers.extensions }
58
58
 
59
59
  class DetailsKey #:nodoc:
60
60
  alias :eql? :equal?
61
- alias :object_hash :hash
62
61
 
63
- attr_reader :hash
64
- @details_keys = ThreadSafe::Cache.new
62
+ @details_keys = Concurrent::Map.new
63
+ @digest_cache = Concurrent::Map.new
64
+ @view_context_mutex = Mutex.new
65
65
 
66
- def self.get(details)
66
+ def self.digest_cache(details)
67
+ @digest_cache[details_cache_key(details)] ||= Concurrent::Map.new
68
+ end
69
+
70
+ def self.details_cache_key(details)
67
71
  if details[:formats]
68
72
  details = details.dup
69
- details[:formats] &= Mime::SET.symbols
73
+ details[:formats] &= Template::Types.symbols
70
74
  end
71
- @details_keys[details] ||= new
75
+ @details_keys[details] ||= Object.new
72
76
  end
73
77
 
74
78
  def self.clear
79
+ ActionView::ViewPaths.all_view_paths.each do |path_set|
80
+ path_set.each(&:clear_cache)
81
+ end
82
+ ActionView::LookupContext.fallbacks.each(&:clear_cache)
83
+ @view_context_class = nil
75
84
  @details_keys.clear
85
+ @digest_cache.clear
76
86
  end
77
87
 
78
- def initialize
79
- @hash = object_hash
88
+ def self.digest_caches
89
+ @digest_cache.values
90
+ end
91
+
92
+ def self.view_context_class(klass)
93
+ @view_context_mutex.synchronize do
94
+ @view_context_class ||= klass.with_empty_template_cache
95
+ end
80
96
  end
81
97
  end
82
98
 
@@ -87,7 +103,7 @@ module ActionView
87
103
  # Calculate the details key. Remove the handlers from calculation to improve performance
88
104
  # since the user cannot modify it explicitly.
89
105
  def details_key #:nodoc:
90
- @details_key ||= DetailsKey.get(@details) if @cache
106
+ @details_key ||= DetailsKey.details_cache_key(@details) if @cache
91
107
  end
92
108
 
93
109
  # Temporary skip passing the details_key forward.
@@ -98,10 +114,10 @@ module ActionView
98
114
  @cache = old_value
99
115
  end
100
116
 
101
- protected
102
-
103
- def _set_detail(key, value)
104
- @details = @details.dup if @details_key
117
+ private
118
+ def _set_detail(key, value) # :doc:
119
+ @details = @details.dup if @digest_cache || @details_key
120
+ @digest_cache = nil
105
121
  @details_key = nil
106
122
  @details[key] = value
107
123
  end
@@ -111,59 +127,71 @@ module ActionView
111
127
  module ViewPaths
112
128
  attr_reader :view_paths, :html_fallback_for_js
113
129
 
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
130
  def find(name, prefixes = [], partial = false, keys = [], options = {})
121
131
  @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
122
132
  end
123
133
  alias :find_template :find
124
134
 
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
135
+ alias :find_file :find
136
+ deprecate :find_file
128
137
 
129
138
  def find_all(name, prefixes = [], partial = false, keys = [], options = {})
130
139
  @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
131
140
  end
132
141
 
133
- def exists?(name, prefixes = [], partial = false, keys = [], options = {})
142
+ def exists?(name, prefixes = [], partial = false, keys = [], **options)
134
143
  @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
135
144
  end
136
145
  alias :template_exists? :exists?
137
146
 
147
+ def any?(name, prefixes = [], partial = false)
148
+ @view_paths.exists?(*args_for_any(name, prefixes, partial))
149
+ end
150
+ alias :any_templates? :any?
151
+
138
152
  # Adds fallbacks to the view paths. Useful in cases when you are rendering
139
153
  # a :file.
140
154
  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
155
+ view_paths = build_view_paths((@view_paths.paths + self.class.fallbacks).uniq)
156
+
157
+ if block_given?
158
+ ActiveSupport::Deprecation.warn <<~eowarn.squish
159
+ Calling `with_fallbacks` with a block is deprecated. Call methods on
160
+ the lookup context returned by `with_fallbacks` instead.
161
+ eowarn
162
+
163
+ begin
164
+ _view_paths = @view_paths
165
+ @view_paths = view_paths
166
+ yield
167
+ ensure
168
+ @view_paths = _view_paths
169
+ end
170
+ else
171
+ ActionView::LookupContext.new(view_paths, @details, @prefixes)
146
172
  end
147
- yield
148
- ensure
149
- added_resolvers.times { view_paths.pop }
150
173
  end
151
174
 
152
- protected
175
+ private
176
+ # Whenever setting view paths, makes a copy so that we can manipulate them in
177
+ # instance objects as we wish.
178
+ def build_view_paths(paths)
179
+ ActionView::PathSet.new(Array(paths))
180
+ end
153
181
 
154
- def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
182
+ def args_for_lookup(name, prefixes, partial, keys, details_options)
155
183
  name, prefixes = normalize_name(name, prefixes)
156
184
  details, details_key = detail_args_for(details_options)
157
185
  [name, prefixes, partial || false, details, details_key, keys]
158
186
  end
159
187
 
160
188
  # Compute details hash and key according to user options (e.g. passed from #render).
161
- def detail_args_for(options)
189
+ def detail_args_for(options) # :doc:
162
190
  return @details, details_key if options.empty? # most common path.
163
191
  user_details = @details.merge(options)
164
192
 
165
193
  if @cache
166
- details_key = DetailsKey.get(user_details)
194
+ details_key = DetailsKey.details_cache_key(user_details)
167
195
  else
168
196
  details_key = nil
169
197
  end
@@ -171,18 +199,44 @@ module ActionView
171
199
  [user_details, details_key]
172
200
  end
173
201
 
202
+ def args_for_any(name, prefixes, partial)
203
+ name, prefixes = normalize_name(name, prefixes)
204
+ details, details_key = detail_args_for_any
205
+ [name, prefixes, partial || false, details, details_key]
206
+ end
207
+
208
+ def detail_args_for_any
209
+ @detail_args_for_any ||= begin
210
+ details = {}
211
+
212
+ registered_details.each do |k|
213
+ if k == :variants
214
+ details[k] = :any
215
+ else
216
+ details[k] = Accessors::DEFAULT_PROCS[k].call
217
+ end
218
+ end
219
+
220
+ if @cache
221
+ [details, DetailsKey.details_cache_key(details)]
222
+ else
223
+ [details, nil]
224
+ end
225
+ end
226
+ end
227
+
174
228
  # Support legacy foo.erb names even though we now ignore .erb
175
229
  # as well as incorrectly putting part of the path in the template
176
230
  # name instead of the prefix.
177
- def normalize_name(name, prefixes) #:nodoc:
231
+ def normalize_name(name, prefixes)
178
232
  prefixes = prefixes.presence
179
- parts = name.to_s.split('/')
233
+ parts = name.to_s.split("/")
180
234
  parts.shift if parts.first.empty?
181
- name = parts.pop
235
+ name = parts.pop
182
236
 
183
237
  return name, prefixes || [""] if parts.empty?
184
238
 
185
- parts = parts.join('/')
239
+ parts = parts.join("/")
186
240
  prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
187
241
 
188
242
  return name, prefixes
@@ -194,21 +248,47 @@ module ActionView
194
248
  include ViewPaths
195
249
 
196
250
  def initialize(view_paths, details = {}, prefixes = [])
197
- @details, @details_key = {}, nil
198
- @skip_default_locale = false
251
+ @details_key = nil
252
+ @digest_cache = nil
199
253
  @cache = true
200
254
  @prefixes = prefixes
201
- @rendered_format = nil
202
255
 
203
- self.view_paths = view_paths
204
- initialize_details(details)
256
+ @details = initialize_details({}, details)
257
+ @view_paths = build_view_paths(view_paths)
258
+ end
259
+
260
+ def digest_cache
261
+ @digest_cache ||= DetailsKey.digest_cache(@details)
262
+ end
263
+
264
+ def with_prepended_formats(formats)
265
+ details = @details.dup
266
+ details[:formats] = formats
267
+
268
+ self.class.new(@view_paths, details, @prefixes)
205
269
  end
206
270
 
271
+ def initialize_details(target, details)
272
+ registered_details.each do |k|
273
+ target[k] = details[k] || Accessors::DEFAULT_PROCS[k].call
274
+ end
275
+ target
276
+ end
277
+ private :initialize_details
278
+
207
279
  # Override formats= to expand ["*/*"] values and automatically
208
280
  # add :html as fallback to :js.
209
281
  def formats=(values)
210
282
  if values
283
+ values = values.dup
211
284
  values.concat(default_formats) if values.delete "*/*"
285
+ values.uniq!
286
+
287
+ invalid_values = (values - Template::Types.symbols)
288
+ unless invalid_values.empty?
289
+ raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
290
+ end
291
+
212
292
  if values == [:js]
213
293
  values << :html
214
294
  @html_fallback_for_js = true
@@ -217,12 +297,6 @@ module ActionView
217
297
  super(values)
218
298
  end
219
299
 
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
300
  # Override locale to return a symbol instead of array.
227
301
  def locale
228
302
  @details[:locale].first
@@ -237,23 +311,7 @@ module ActionView
237
311
  config.locale = value
238
312
  end
239
313
 
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
314
+ super(default_locale)
257
315
  end
258
316
  end
259
317
  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,47 @@ 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
51
+ alias :find_file :find
52
+ deprecate :find_file
52
53
 
53
54
  def find_all(path, prefixes = [], *args)
54
- _find_all path, prefixes, args, false
55
+ _find_all path, prefixes, args
55
56
  end
56
57
 
57
58
  def exists?(path, prefixes, *args)
58
59
  find_all(path, prefixes, *args).any?
59
60
  end
60
61
 
61
- private
62
+ def find_all_with_query(query) # :nodoc:
63
+ paths.each do |resolver|
64
+ templates = resolver.find_all_with_query(query)
65
+ return templates unless templates.empty?
66
+ end
62
67
 
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
68
+ []
69
+ end
70
+
71
+ private
72
+ def _find_all(path, prefixes, args)
73
+ prefixes = [prefixes] if String === prefixes
74
+ prefixes.each do |prefix|
75
+ paths.each do |resolver|
70
76
  templates = resolver.find_all(path, prefix, *args)
77
+ return templates unless templates.empty?
71
78
  end
72
- return templates unless templates.empty?
73
79
  end
80
+ []
74
81
  end
75
- []
76
- end
77
82
 
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
83
+ def typecast(paths)
84
+ paths.map do |path|
85
+ case path
86
+ when Pathname, String
87
+ OptimizedFileSystemResolver.new path.to_s
88
+ else
89
+ path
90
+ end
85
91
  end
86
92
  end
87
- end
88
93
  end
89
94
  end
@@ -1,11 +1,18 @@
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:
9
+ NULL_OPTION = Object.new
10
+
7
11
  config.action_view = ActiveSupport::OrderedOptions.new
8
- config.action_view.embed_authenticity_token_in_remote_forms = false
12
+ config.action_view.embed_authenticity_token_in_remote_forms = nil
13
+ config.action_view.debug_missing_translation = true
14
+ config.action_view.default_enforce_utf8 = nil
15
+ config.action_view.finalize_compiled_template_methods = NULL_OPTION
9
16
 
10
17
  config.eager_load_namespaces << ActionView
11
18
 
@@ -16,13 +23,48 @@ module ActionView
16
23
  end
17
24
  end
18
25
 
26
+ initializer "action_view.form_with_generates_remote_forms" do |app|
27
+ ActiveSupport.on_load(:action_view) do
28
+ form_with_generates_remote_forms = app.config.action_view.delete(:form_with_generates_remote_forms)
29
+ ActionView::Helpers::FormHelper.form_with_generates_remote_forms = form_with_generates_remote_forms
30
+ end
31
+ end
32
+
33
+ initializer "action_view.form_with_generates_ids" do |app|
34
+ ActiveSupport.on_load(:action_view) do
35
+ form_with_generates_ids = app.config.action_view.delete(:form_with_generates_ids)
36
+ unless form_with_generates_ids.nil?
37
+ ActionView::Helpers::FormHelper.form_with_generates_ids = form_with_generates_ids
38
+ end
39
+ end
40
+ end
41
+
42
+ initializer "action_view.default_enforce_utf8" do |app|
43
+ ActiveSupport.on_load(:action_view) do
44
+ default_enforce_utf8 = app.config.action_view.delete(:default_enforce_utf8)
45
+ unless default_enforce_utf8.nil?
46
+ ActionView::Helpers::FormTagHelper.default_enforce_utf8 = default_enforce_utf8
47
+ end
48
+ end
49
+ end
50
+
51
+ initializer "action_view.finalize_compiled_template_methods" do |app|
52
+ ActiveSupport.on_load(:action_view) do
53
+ option = app.config.action_view.delete(:finalize_compiled_template_methods)
54
+
55
+ if option != NULL_OPTION
56
+ ActiveSupport::Deprecation.warn "action_view.finalize_compiled_template_methods is deprecated and has no effect"
57
+ end
58
+ end
59
+ end
60
+
19
61
  initializer "action_view.logger" do
20
62
  ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger }
21
63
  end
22
64
 
23
65
  initializer "action_view.set_configs" do |app|
24
66
  ActiveSupport.on_load(:action_view) do
25
- app.config.action_view.each do |k,v|
67
+ app.config.action_view.each do |k, v|
26
68
  send "#{k}=", v
27
69
  end
28
70
  end
@@ -36,14 +78,28 @@ module ActionView
36
78
  end
37
79
  end
38
80
 
81
+ initializer "action_view.per_request_digest_cache" do |app|
82
+ ActiveSupport.on_load(:action_view) do
83
+ unless ActionView::Resolver.caching?
84
+ app.executor.to_run ActionView::CacheExpiry::Executor.new(watcher: app.config.file_watcher)
85
+ end
86
+ end
87
+ end
88
+
39
89
  initializer "action_view.setup_action_pack" do |app|
40
90
  ActiveSupport.on_load(:action_controller) do
41
- ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor)
91
+ ActionView::RoutingUrlFor.include(ActionDispatch::Routing::UrlFor)
42
92
  end
43
93
  end
44
94
 
45
- rake_tasks do
46
- load "action_view/tasks/dependencies.rake"
95
+ initializer "action_view.collection_caching", after: "action_controller.set_configs" do |app|
96
+ PartialRenderer.collection_cache = app.config.action_controller.cache_store
97
+ end
98
+
99
+ rake_tasks do |app|
100
+ unless app.config.api_only
101
+ load "action_view/tasks/cache_digests.rake"
102
+ end
47
103
  end
48
104
  end
49
105
  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