actionview 6.0.3.3 → 6.1.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +177 -208
  3. data/MIT-LICENSE +1 -1
  4. data/lib/action_view.rb +4 -1
  5. data/lib/action_view/base.rb +19 -50
  6. data/lib/action_view/cache_expiry.rb +1 -2
  7. data/lib/action_view/dependency_tracker.rb +10 -4
  8. data/lib/action_view/digestor.rb +3 -2
  9. data/lib/action_view/gem_version.rb +3 -3
  10. data/lib/action_view/helpers/asset_tag_helper.rb +55 -15
  11. data/lib/action_view/helpers/asset_url_helper.rb +6 -4
  12. data/lib/action_view/helpers/atom_feed_helper.rb +2 -1
  13. data/lib/action_view/helpers/cache_helper.rb +10 -16
  14. data/lib/action_view/helpers/date_helper.rb +4 -4
  15. data/lib/action_view/helpers/form_helper.rb +66 -30
  16. data/lib/action_view/helpers/form_options_helper.rb +7 -16
  17. data/lib/action_view/helpers/form_tag_helper.rb +7 -7
  18. data/lib/action_view/helpers/javascript_helper.rb +3 -3
  19. data/lib/action_view/helpers/number_helper.rb +6 -6
  20. data/lib/action_view/helpers/rendering_helper.rb +11 -3
  21. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  22. data/lib/action_view/helpers/tag_helper.rb +92 -17
  23. data/lib/action_view/helpers/tags/base.rb +9 -5
  24. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  25. data/lib/action_view/helpers/tags/date_select.rb +2 -2
  26. data/lib/action_view/helpers/tags/datetime_local_field.rb +1 -1
  27. data/lib/action_view/helpers/tags/label.rb +4 -0
  28. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  29. data/lib/action_view/helpers/tags/select.rb +1 -1
  30. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  31. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  32. data/lib/action_view/helpers/text_helper.rb +1 -1
  33. data/lib/action_view/helpers/translation_helper.rb +87 -51
  34. data/lib/action_view/helpers/url_helper.rb +107 -13
  35. data/lib/action_view/layouts.rb +3 -2
  36. data/lib/action_view/log_subscriber.rb +26 -10
  37. data/lib/action_view/lookup_context.rb +3 -18
  38. data/lib/action_view/path_set.rb +0 -3
  39. data/lib/action_view/railtie.rb +39 -46
  40. data/lib/action_view/renderer/abstract_renderer.rb +93 -14
  41. data/lib/action_view/renderer/collection_renderer.rb +196 -0
  42. data/lib/action_view/renderer/object_renderer.rb +34 -0
  43. data/lib/action_view/renderer/partial_renderer.rb +20 -282
  44. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +25 -26
  45. data/lib/action_view/renderer/renderer.rb +44 -1
  46. data/lib/action_view/renderer/streaming_template_renderer.rb +5 -1
  47. data/lib/action_view/renderer/template_renderer.rb +15 -12
  48. data/lib/action_view/rendering.rb +3 -1
  49. data/lib/action_view/routing_url_for.rb +1 -1
  50. data/lib/action_view/template.rb +9 -49
  51. data/lib/action_view/template/handlers.rb +0 -26
  52. data/lib/action_view/template/handlers/erb.rb +10 -14
  53. data/lib/action_view/template/handlers/erb/erubi.rb +9 -7
  54. data/lib/action_view/template/html.rb +1 -11
  55. data/lib/action_view/template/raw_file.rb +0 -3
  56. data/lib/action_view/template/renderable.rb +24 -0
  57. data/lib/action_view/template/resolver.rb +82 -40
  58. data/lib/action_view/template/text.rb +0 -3
  59. data/lib/action_view/test_case.rb +18 -25
  60. data/lib/action_view/testing/resolvers.rb +10 -31
  61. data/lib/action_view/unbound_template.rb +3 -3
  62. data/lib/action_view/view_paths.rb +34 -36
  63. metadata +18 -15
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2019 David Heinemeier Hansson
1
+ Copyright (c) 2004-2020 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2019 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2020 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -51,6 +51,8 @@ module ActionView
51
51
  autoload :Renderer
52
52
  autoload :AbstractRenderer
53
53
  autoload :PartialRenderer
54
+ autoload :CollectionRenderer
55
+ autoload :ObjectRenderer
54
56
  autoload :TemplateRenderer
55
57
  autoload :StreamingTemplateRenderer
56
58
  end
@@ -58,6 +60,7 @@ module ActionView
58
60
  autoload_at "action_view/template/resolver" do
59
61
  autoload :Resolver
60
62
  autoload :PathResolver
63
+ autoload :FileSystemResolver
61
64
  autoload :OptimizedFileSystemResolver
62
65
  autoload :FallbackFileSystemResolver
63
66
  end
@@ -3,7 +3,6 @@
3
3
  require "active_support/core_ext/module/attr_internal"
4
4
  require "active_support/core_ext/module/attribute_accessors"
5
5
  require "active_support/ordered_options"
6
- require "active_support/deprecation"
7
6
  require "action_view/log_subscriber"
8
7
  require "action_view/helpers"
9
8
  require "action_view/context"
@@ -28,7 +27,7 @@ module ActionView #:nodoc:
28
27
  # Name: <%= person.name %><br/>
29
28
  # <% end %>
30
29
  #
31
- # The loop is setup in regular embedding tags <tt><% %></tt>, and the name is written using the output embedding tag <tt><%= %></tt>. Note that this
30
+ # The loop is set up in regular embedding tags <tt><% %></tt>, and the name is written using the output embedding tag <tt><%= %></tt>. Note that this
32
31
  # is not just a usage suggestion. Regular output functions like print or puts won't work with ERB templates. So this would be wrong:
33
32
  #
34
33
  # <%# WRONG %>
@@ -152,7 +151,7 @@ module ActionView #:nodoc:
152
151
  # Specify whether rendering within namespaced controllers should prefix
153
152
  # the partial paths for ActiveModel objects with the namespace.
154
153
  # (e.g., an Admin::PostsController would render @post using /admin/posts/_post.erb)
155
- cattr_accessor :prefix_partial_path_with_controller_namespace, default: true
154
+ class_attribute :prefix_partial_path_with_controller_namespace, default: true
156
155
 
157
156
  # Specify default_formats that can be rendered.
158
157
  cattr_accessor :default_formats
@@ -163,6 +162,9 @@ module ActionView #:nodoc:
163
162
  # Specify whether submit_tag should automatically disable on click
164
163
  cattr_accessor :automatically_disable_submit_tag, default: true
165
164
 
165
+ # Annotate rendered view with file names
166
+ cattr_accessor :annotate_rendered_view_with_filenames, default: false
167
+
166
168
  class_attribute :_routes
167
169
  class_attribute :logger
168
170
 
@@ -188,6 +190,10 @@ module ActionView #:nodoc:
188
190
  # correctly.
189
191
  define_method(:compiled_method_container) { subclass }
190
192
  define_singleton_method(:compiled_method_container) { subclass }
193
+
194
+ def inspect
195
+ "#<ActionView::Base:#{'%#016x' % (object_id << 1)}>"
196
+ end
191
197
  }
192
198
  end
193
199
 
@@ -207,21 +213,6 @@ module ActionView #:nodoc:
207
213
 
208
214
  # :stopdoc:
209
215
 
210
- def self.build_lookup_context(context)
211
- case context
212
- when ActionView::Renderer
213
- context.lookup_context
214
- when Array
215
- ActionView::LookupContext.new(context)
216
- when ActionView::PathSet
217
- ActionView::LookupContext.new(context)
218
- when nil
219
- ActionView::LookupContext.new([])
220
- else
221
- raise NotImplementedError, context.class.name
222
- end
223
- end
224
-
225
216
  def self.empty
226
217
  with_view_paths([])
227
218
  end
@@ -234,58 +225,36 @@ module ActionView #:nodoc:
234
225
  new context, assigns, controller
235
226
  end
236
227
 
237
- NULL = Object.new
238
-
239
228
  # :startdoc:
240
229
 
241
- def initialize(lookup_context = nil, assigns = {}, controller = nil, formats = NULL) #:nodoc:
230
+ def initialize(lookup_context, assigns, controller) #:nodoc:
242
231
  @_config = ActiveSupport::InheritableOptions.new
243
232
 
244
- unless formats == NULL
245
- ActiveSupport::Deprecation.warn <<~eowarn.squish
246
- Passing formats to ActionView::Base.new is deprecated
247
- eowarn
248
- end
249
-
250
- case lookup_context
251
- when ActionView::LookupContext
252
- @lookup_context = lookup_context
253
- else
254
- ActiveSupport::Deprecation.warn <<~eowarn.squish
255
- ActionView::Base instances should be constructed with a lookup context,
256
- assignments, and a controller.
257
- eowarn
258
- @lookup_context = self.class.build_lookup_context(lookup_context)
259
- end
233
+ @lookup_context = lookup_context
260
234
 
261
235
  @view_renderer = ActionView::Renderer.new @lookup_context
262
236
  @current_template = nil
263
237
 
264
- @cache_hit = {}
265
238
  assign(assigns)
266
239
  assign_controller(controller)
267
240
  _prepare_context
268
241
  end
269
242
 
270
- def _run(method, template, locals, buffer, &block)
243
+ def _run(method, template, locals, buffer, add_to_stack: true, &block)
271
244
  _old_output_buffer, _old_virtual_path, _old_template = @output_buffer, @virtual_path, @current_template
272
- @current_template = template
245
+ @current_template = template if add_to_stack
273
246
  @output_buffer = buffer
274
- send(method, locals, buffer, &block)
247
+ public_send(method, locals, buffer, &block)
275
248
  ensure
276
249
  @output_buffer, @virtual_path, @current_template = _old_output_buffer, _old_virtual_path, _old_template
277
250
  end
278
251
 
279
252
  def compiled_method_container
280
- if self.class == ActionView::Base
281
- ActiveSupport::Deprecation.warn <<~eowarn.squish
282
- ActionView::Base instances must implement `compiled_method_container`
283
- or use the class method `with_empty_template_cache` for constructing
284
- an ActionView::Base instance that has an empty cache.
285
- eowarn
286
- end
287
-
288
- self.class
253
+ raise NotImplementedError, <<~msg.squish
254
+ Subclasses of ActionView::Base must implement `compiled_method_container`
255
+ or use the class method `with_empty_template_cache` for constructing
256
+ an ActionView::Base subclass that has an empty cache.
257
+ msg
289
258
  end
290
259
 
291
260
  def in_rendering_context(options)
@@ -42,8 +42,7 @@ module ActionView
42
42
 
43
43
  private
44
44
  def dirs_to_watch
45
- fs_paths = all_view_paths.grep(FileSystemResolver)
46
- fs_paths.map(&:path).sort.uniq
45
+ all_view_paths.grep(FileSystemResolver).map!(&:path).tap(&:uniq!).sort!
47
46
  end
48
47
 
49
48
  def all_view_paths
@@ -130,8 +130,9 @@ module ActionView
130
130
 
131
131
  def add_dependencies(render_dependencies, arguments, pattern)
132
132
  arguments.scan(pattern) do
133
- add_dynamic_dependency(render_dependencies, Regexp.last_match[:dynamic])
134
- add_static_dependency(render_dependencies, Regexp.last_match[:static])
133
+ match = Regexp.last_match
134
+ add_dynamic_dependency(render_dependencies, match[:dynamic])
135
+ add_static_dependency(render_dependencies, match[:static], match[:quote])
135
136
  end
136
137
  end
137
138
 
@@ -141,7 +142,12 @@ module ActionView
141
142
  end
142
143
  end
143
144
 
144
- def add_static_dependency(dependencies, dependency)
145
+ def add_static_dependency(dependencies, dependency, quote_type)
146
+ if quote_type == '"'
147
+ # Ignore if there is interpolation
148
+ return if dependency.include?('#{')
149
+ end
150
+
145
151
  if dependency
146
152
  if dependency.include?("/")
147
153
  dependencies << dependency
@@ -164,7 +170,7 @@ module ActionView
164
170
  def explicit_dependencies
165
171
  dependencies = source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
166
172
 
167
- wildcards, explicits = dependencies.partition { |dependency| dependency[-1] == "*" }
173
+ wildcards, explicits = dependencies.partition { |dependency| dependency.end_with?("*") }
168
174
 
169
175
  (explicits + resolve_directories(wildcards)).uniq
170
176
  end
@@ -41,8 +41,9 @@ module ActionView
41
41
  # Create a dependency tree for template named +name+.
42
42
  def tree(name, finder, partial = false, seen = {})
43
43
  logical_name = name.gsub(%r|/_|, "/")
44
+ interpolated = name.include?("#")
44
45
 
45
- if template = find_template(finder, logical_name, [], partial, [])
46
+ if !interpolated && (template = find_template(finder, logical_name, [], partial, []))
46
47
  if node = seen[template.identifier] # handle cycles in the tree
47
48
  node
48
49
  else
@@ -55,7 +56,7 @@ module ActionView
55
56
  node
56
57
  end
57
58
  else
58
- unless name.include?("#") # Dynamic template partial names can never be tracked
59
+ unless interpolated # Dynamic template partial names can never be tracked
59
60
  logger.error " Couldn't find template for digesting: #{name}"
60
61
  end
61
62
 
@@ -8,9 +8,9 @@ module ActionView
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 6
11
- MINOR = 0
12
- TINY = 3
13
- PRE = "3"
11
+ MINOR = 1
12
+ TINY = 1
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -3,7 +3,6 @@
3
3
  require "active_support/core_ext/array/extract_options"
4
4
  require "active_support/core_ext/hash/keys"
5
5
  require "active_support/core_ext/object/inclusion"
6
- require "active_support/core_ext/object/try"
7
6
  require "action_view/helpers/asset_url_helper"
8
7
  require "action_view/helpers/tag_helper"
9
8
 
@@ -24,13 +23,15 @@ module ActionView
24
23
  include AssetUrlHelper
25
24
  include TagHelper
26
25
 
26
+ mattr_accessor :preload_links_header
27
+
27
28
  # Returns an HTML script tag for each of the +sources+ provided.
28
29
  #
29
30
  # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
30
31
  # to <tt>assets/javascripts</tt>, full paths are assumed to be relative to the document
31
32
  # root. Relative paths are idiomatic, use absolute paths only when needed.
32
33
  #
33
- # When passing paths, the ".js" extension is optional. If you do not want ".js"
34
+ # When passing paths, the ".js" extension is optional. If you do not want ".js"
34
35
  # appended to the path <tt>extname: false</tt> can be set on the options.
35
36
  #
36
37
  # You can modify the HTML attributes of the script tag by passing a hash as the
@@ -87,13 +88,24 @@ module ActionView
87
88
  def javascript_include_tag(*sources)
88
89
  options = sources.extract_options!.stringify_keys
89
90
  path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
90
- early_hints_links = []
91
+ preload_links = []
92
+ nopush = options["nopush"].nil? ? true : options.delete("nopush")
93
+ crossorigin = options.delete("crossorigin")
94
+ crossorigin = "anonymous" if crossorigin == true
95
+ integrity = options["integrity"]
91
96
 
92
97
  sources_tags = sources.uniq.map { |source|
93
98
  href = path_to_javascript(source, path_options)
94
- early_hints_links << "<#{href}>; rel=preload; as=script"
99
+ if preload_links_header && !options["defer"]
100
+ preload_link = "<#{href}>; rel=preload; as=script"
101
+ preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
102
+ preload_link += "; integrity=#{integrity}" unless integrity.nil?
103
+ preload_link += "; nopush" if nopush
104
+ preload_links << preload_link
105
+ end
95
106
  tag_options = {
96
- "src" => href
107
+ "src" => href,
108
+ "crossorigin" => crossorigin
97
109
  }.merge!(options)
98
110
  if tag_options["nonce"] == true
99
111
  tag_options["nonce"] = content_security_policy_nonce
@@ -101,7 +113,9 @@ module ActionView
101
113
  content_tag("script", "", tag_options)
102
114
  }.join("\n").html_safe
103
115
 
104
- request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request
116
+ if preload_links_header
117
+ send_preload_links_header(preload_links)
118
+ end
105
119
 
106
120
  sources_tags
107
121
  end
@@ -137,20 +151,33 @@ module ActionView
137
151
  def stylesheet_link_tag(*sources)
138
152
  options = sources.extract_options!.stringify_keys
139
153
  path_options = options.extract!("protocol", "host", "skip_pipeline").symbolize_keys
140
- early_hints_links = []
154
+ preload_links = []
155
+ crossorigin = options.delete("crossorigin")
156
+ crossorigin = "anonymous" if crossorigin == true
157
+ nopush = options["nopush"].nil? ? true : options.delete("nopush")
158
+ integrity = options["integrity"]
141
159
 
142
160
  sources_tags = sources.uniq.map { |source|
143
161
  href = path_to_stylesheet(source, path_options)
144
- early_hints_links << "<#{href}>; rel=preload; as=style"
162
+ if preload_links_header
163
+ preload_link = "<#{href}>; rel=preload; as=style"
164
+ preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
165
+ preload_link += "; integrity=#{integrity}" unless integrity.nil?
166
+ preload_link += "; nopush" if nopush
167
+ preload_links << preload_link
168
+ end
145
169
  tag_options = {
146
170
  "rel" => "stylesheet",
147
171
  "media" => "screen",
172
+ "crossorigin" => crossorigin,
148
173
  "href" => href
149
174
  }.merge!(options)
150
175
  tag(:link, tag_options)
151
176
  }.join("\n").html_safe
152
177
 
153
- request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request
178
+ if preload_links_header
179
+ send_preload_links_header(preload_links)
180
+ end
154
181
 
155
182
  sources_tags
156
183
  end
@@ -241,6 +268,7 @@ module ActionView
241
268
  # * <tt>:as</tt> - Override the auto-generated value for as attribute, calculated using +source+ extension and mime type.
242
269
  # * <tt>:crossorigin</tt> - Specify the crossorigin attribute, required to load cross-origin resources.
243
270
  # * <tt>:nopush</tt> - Specify if the use of server push is not desired for the resource. Defaults to +false+.
271
+ # * <tt>:integrity</tt> - Specify the integrity attribute.
244
272
  #
245
273
  # ==== Examples
246
274
  #
@@ -268,10 +296,11 @@ module ActionView
268
296
  def preload_link_tag(source, options = {})
269
297
  href = asset_path(source, skip_pipeline: options.delete(:skip_pipeline))
270
298
  extname = File.extname(source).downcase.delete(".")
271
- mime_type = options.delete(:type) || Template::Types[extname].try(:to_s)
299
+ mime_type = options.delete(:type) || Template::Types[extname]&.to_s
272
300
  as_type = options.delete(:as) || resolve_link_as(extname, mime_type)
273
301
  crossorigin = options.delete(:crossorigin)
274
302
  crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
303
+ integrity = options[:integrity]
275
304
  nopush = options.delete(:nopush) || false
276
305
 
277
306
  link_tag = tag.link(**{
@@ -282,12 +311,13 @@ module ActionView
282
311
  crossorigin: crossorigin
283
312
  }.merge!(options.symbolize_keys))
284
313
 
285
- early_hints_link = "<#{href}>; rel=preload; as=#{as_type}"
286
- early_hints_link += "; type=#{mime_type}" if mime_type
287
- early_hints_link += "; crossorigin=#{crossorigin}" if crossorigin
288
- early_hints_link += "; nopush" if nopush
314
+ preload_link = "<#{href}>; rel=preload; as=#{as_type}"
315
+ preload_link += "; type=#{mime_type}" if mime_type
316
+ preload_link += "; crossorigin=#{crossorigin}" if crossorigin
317
+ preload_link += "; integrity=#{integrity}" if integrity
318
+ preload_link += "; nopush" if nopush
289
319
 
290
- request.send_early_hints("Link" => early_hints_link) if respond_to?(:request) && request
320
+ send_preload_links_header([preload_link])
291
321
 
292
322
  link_tag
293
323
  end
@@ -483,6 +513,16 @@ module ActionView
483
513
  type
484
514
  end
485
515
  end
516
+
517
+ def send_preload_links_header(preload_links)
518
+ if respond_to?(:request) && request
519
+ request.send_early_hints("Link" => preload_links.join("\n"))
520
+ end
521
+
522
+ if respond_to?(:response) && response
523
+ response.headers["Link"] = [response.headers["Link"].presence, *preload_links].compact.join(",")
524
+ end
525
+ end
486
526
  end
487
527
  end
488
528
  end
@@ -52,7 +52,7 @@ module ActionView
52
52
  # solution being slower. You should be sure to measure your actual
53
53
  # performance across targeted browsers both before and after this change.
54
54
  #
55
- # To implement the corresponding hosts you can either setup four actual
55
+ # To implement the corresponding hosts you can either set up four actual
56
56
  # hosts or use wildcard DNS to CNAME the wildcard to a single asset host.
57
57
  # You can read more about setting up your DNS CNAME records from your ISP.
58
58
  #
@@ -80,7 +80,7 @@ module ActionView
80
80
  # absolute path of the asset, for example "/assets/rails.png".
81
81
  #
82
82
  # ActionController::Base.asset_host = Proc.new { |source|
83
- # if source.ends_with?('.css')
83
+ # if source.end_with?('.css')
84
84
  # "http://stylesheets.example.com"
85
85
  # else
86
86
  # "http://assets.example.com"
@@ -98,7 +98,7 @@ module ActionView
98
98
  # have SSL certificates for each of the asset hosts this technique allows you
99
99
  # to avoid warnings in the client about mixed media.
100
100
  # Note that the +request+ parameter might not be supplied, e.g. when the assets
101
- # are precompiled with the command `rails assets:precompile`. Make sure to use a
101
+ # are precompiled with the command `bin/rails assets:precompile`. Make sure to use a
102
102
  # +Proc+ instead of a lambda, since a +Proc+ allows missing parameters and sets them
103
103
  # to +nil+.
104
104
  #
@@ -133,6 +133,8 @@ module ActionView
133
133
  # which is implemented by sprockets-rails.
134
134
  #
135
135
  # asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js"
136
+ # asset_path('application.js', host: 'example.com') # => "//example.com/assets/application.js"
137
+ # asset_path("application.js", host: 'example.com', protocol: 'https') # => "https://example.com/assets/application.js"
136
138
  #
137
139
  # === Without the asset pipeline (<tt>skip_pipeline: true</tt>)
138
140
  #
@@ -204,7 +206,7 @@ module ActionView
204
206
 
205
207
  relative_url_root = defined?(config.relative_url_root) && config.relative_url_root
206
208
  if relative_url_root
207
- source = File.join(relative_url_root, source) unless source.starts_with?("#{relative_url_root}/")
209
+ source = File.join(relative_url_root, source) unless source.start_with?("#{relative_url_root}/")
208
210
  end
209
211
 
210
212
  if host = compute_asset_host(source, options)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "set"
4
+ require "active_support/core_ext/symbol/starts_ends_with"
4
5
 
5
6
  module ActionView
6
7
  # = Action View Atom Feed Helpers
@@ -115,7 +116,7 @@ module ActionView
115
116
  end
116
117
 
117
118
  feed_opts = { "xml:lang" => options[:language] || "en-US", "xmlns" => "http://www.w3.org/2005/Atom" }
118
- feed_opts.merge!(options).reject! { |k, v| !k.to_s.match(/^xml/) }
119
+ feed_opts.merge!(options).select! { |k, _| k.start_with?("xml") }
119
120
 
120
121
  xml.feed(feed_opts) do
121
122
  xml.id(options[:id] || "tag:#{request.host},#{options[:schema_date]}:#{request.fullpath.split(".")[0]}")