actionview 8.0.2.1 → 8.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b10a94983cf19c0bd7a2e4a1d5243ef133b98650f36a8afff60a9d980682ba7
4
- data.tar.gz: 83b1cf28672cc2b57d06bf3e611d09ef869260304ec96372ec63972f2ee1a5b6
3
+ metadata.gz: d906f994cc2a7151f2763ccfd5505479b2ba0dd408797b28716d495b4ec89089
4
+ data.tar.gz: 10cb316f59e90d20729c7f61ec92c0e3b6b28e359ea13b2692736e5ffbe7e7a4
5
5
  SHA512:
6
- metadata.gz: 615c6ea6b985372edbb93621b555517b20ddfa12423cd20dbd80bf20f9393b93def8c80e2a9c9cd0f9203d0bb0588a7f1bf97f07d2c6799906f27eb63e0084fd
7
- data.tar.gz: 4c1f66a2d367b6deafc4aed3c5938985957ac9fec60e53a637f86e8279ef94f3cf43b1b4b42c26f6ab5184e23efcd71aa3c4e6fbb2c6ca3bed4db40b54e31269
6
+ metadata.gz: a845f01c731db0f215c2a7d29888924fa1e50d3c68a17e1ed37e6dd746aa47a3250c7018d6d66639fc9ef7039f0b6d64234110edd310870bdae2074932044356
7
+ data.tar.gz: be07fd924f900d3d8c537652678d941fed5ea46ff657197e2182fdbaf4554923a1f1c41e27873735911a85b7a4d5819c330b35ceacefa90ca542c04e9b6053a8
data/CHANGELOG.md CHANGED
@@ -1,9 +1,26 @@
1
- ## Rails 8.0.2.1 (August 13, 2025) ##
1
+ ## Rails 8.0.3 (September 22, 2025) ##
2
2
 
3
- * No changes.
3
+ * Fix label with `for` option not getting prefixed by form `namespace` value
4
4
 
5
+ *Abeid Ahmed*, *Hartley McGuire*
5
6
 
6
- ## Rails 8.0.2 (March 12, 2025) ##
7
+ * Fix `javascript_include_tag` `type` option to accept either strings and symbols.
8
+
9
+ ```ruby
10
+ javascript_include_tag "application", type: :module
11
+ javascript_include_tag "application", type: "module"
12
+ ```
13
+
14
+ Previously, only the string value was recognized.
15
+
16
+ *Jean Boussier*
17
+
18
+ * Fix `excerpt` helper with non-whitespace separator.
19
+
20
+ *Jonathan Hefner*
21
+
22
+
23
+ ## Rails 8.0.2.1 (August 13, 2025) ##
7
24
 
8
25
  * No changes.
9
26
 
data/README.rdoc CHANGED
@@ -35,6 +35,6 @@ Bug reports for the Ruby on \Rails project can be filed here:
35
35
 
36
36
  * https://github.com/rails/rails/issues
37
37
 
38
- Feature requests should be discussed on the rails-core mailing list here:
38
+ Feature requests should be discussed on the rubyonrails-core forum here:
39
39
 
40
40
  * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -9,8 +9,8 @@ module ActionView
9
9
  module VERSION
10
10
  MAJOR = 8
11
11
  MINOR = 0
12
- TINY = 2
13
- PRE = "1"
12
+ TINY = 3
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -119,7 +119,7 @@ module ActionView
119
119
  crossorigin = options.delete("crossorigin")
120
120
  crossorigin = "anonymous" if crossorigin == true
121
121
  integrity = options["integrity"]
122
- rel = options["type"] == "module" ? "modulepreload" : "preload"
122
+ rel = options["type"] == "module" || options["type"] == :module ? "modulepreload" : "preload"
123
123
 
124
124
  sources_tags = sources.uniq.map { |source|
125
125
  href = path_to_javascript(source, path_options)
@@ -361,7 +361,7 @@ module ActionView
361
361
  crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
362
362
  integrity = options[:integrity]
363
363
  nopush = options.delete(:nopush) || false
364
- rel = mime_type == "module" ? "modulepreload" : "preload"
364
+ rel = mime_type == "module" || mime_type == :module ? "modulepreload" : "preload"
365
365
 
366
366
  link_tag = tag.link(
367
367
  rel: rel,
@@ -170,7 +170,7 @@ module ActionView
170
170
 
171
171
  # Creates an entry tag for a specific record and prefills the id using class and id.
172
172
  #
173
- # Options:
173
+ # ==== Options
174
174
  #
175
175
  # * <tt>:published</tt>: Time first published. Defaults to the created_at attribute on the record if one such exists.
176
176
  # * <tt>:updated</tt>: Time of update. Defaults to the updated_at attribute on the record if one such exists.
@@ -136,8 +136,15 @@ module ActionView
136
136
  from_year += 1 if from_time.month >= 3
137
137
  to_year = to_time.year
138
138
  to_year -= 1 if to_time.month < 3
139
- leap_years = (from_year > to_year) ? 0 : (from_year..to_year).count { |x| Date.leap?(x) }
139
+
140
+ leap_years = if from_year > to_year
141
+ 0
142
+ else
143
+ fyear = from_year - 1
144
+ (to_year / 4 - to_year / 100 + to_year / 400) - (fyear / 4 - fyear / 100 + fyear / 400)
145
+ end
140
146
  minute_offset_for_leap_year = leap_years * 1440
147
+
141
148
  # Discount the leap year days when calculating year distance.
142
149
  # e.g. if there are 20 leap year days between 2 dates having the same day
143
150
  # and month then based on 365 days calculation
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cgi"
3
+ require "cgi/escape"
4
+ require "cgi/util" if RUBY_VERSION < "3.5"
4
5
  require "action_view/helpers/date_helper"
5
6
  require "action_view/helpers/url_helper"
6
7
  require "action_view/helpers/form_tag_helper"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cgi"
3
+ require "cgi/escape"
4
+ require "cgi/util" if RUBY_VERSION < "3.5"
4
5
  require "erb"
5
6
  require "active_support/core_ext/string/output_safety"
6
7
  require "active_support/core_ext/array/extract_options"
@@ -496,7 +497,8 @@ module ActionView
496
497
  # <option value="France">France</option>
497
498
  # </optgroup>
498
499
  #
499
- # Parameters:
500
+ # ==== Parameters
501
+ #
500
502
  # * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
501
503
  # <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
502
504
  # nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
@@ -507,7 +509,8 @@ module ActionView
507
509
  # which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
508
510
  # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
509
511
  #
510
- # Options:
512
+ # ==== Options
513
+ #
511
514
  # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this
512
515
  # prepends an option with a generic prompt - "Please select" - or the given prompt string.
513
516
  # * <tt>:divider</tt> - the divider for the options groups.
@@ -599,7 +602,8 @@ module ActionView
599
602
 
600
603
  # Returns a string of option tags for the days of the week.
601
604
  #
602
- # Options:
605
+ # ====Options
606
+ #
603
607
  # * <tt>:index_as_value</tt> - Defaults to false, set to true to use the indexes from
604
608
  # <tt>I18n.translate("date.day_names")</tt> as the values. By default, Sunday is always 0.
605
609
  # * <tt>:day_format</tt> - The I18n key of the array to use for the weekday options.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cgi"
3
+ require "cgi/escape"
4
+ require "cgi/util" if RUBY_VERSION < "3.5"
4
5
  require "action_view/helpers/content_exfiltration_prevention_helper"
5
6
  require "action_view/helpers/url_helper"
6
7
  require "action_view/helpers/text_helper"
@@ -80,27 +80,27 @@ module ActionView
80
80
  end
81
81
  end
82
82
 
83
- def add_default_name_and_id_for_value(tag_value, options)
83
+ def add_default_name_and_field_for_value(tag_value, options, field = "id")
84
84
  if tag_value.nil?
85
- add_default_name_and_id(options)
85
+ add_default_name_and_field(options, field)
86
86
  else
87
- specified_id = options["id"]
88
- add_default_name_and_id(options)
87
+ specified_field = options[field]
88
+ add_default_name_and_field(options, field)
89
89
 
90
- if specified_id.blank? && options["id"].present?
91
- options["id"] += "_#{sanitized_value(tag_value)}"
90
+ if specified_field.blank? && options[field].present?
91
+ options[field] += "_#{sanitized_value(tag_value)}"
92
92
  end
93
93
  end
94
94
  end
95
95
 
96
- def add_default_name_and_id(options)
96
+ def add_default_name_and_field(options, field = "id")
97
97
  index = name_and_id_index(options)
98
98
  options["name"] = options.fetch("name") { tag_name(options["multiple"], index) }
99
99
 
100
100
  if generate_ids?
101
- options["id"] = options.fetch("id") { tag_id(index, options.delete("namespace")) }
101
+ options[field] = options.fetch(field) { tag_id(index, options.delete("namespace")) }
102
102
  if namespace = options.delete("namespace")
103
- options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace
103
+ options[field] = options[field] ? "#{namespace}_#{options[field]}" : namespace
104
104
  end
105
105
  end
106
106
  end
@@ -21,10 +21,10 @@ module ActionView
21
21
  options["checked"] = "checked" if input_checked?(options)
22
22
 
23
23
  if options["multiple"]
24
- add_default_name_and_id_for_value(@checked_value, options)
24
+ add_default_name_and_field_for_value(@checked_value, options)
25
25
  options.delete("multiple")
26
26
  else
27
- add_default_name_and_id(options)
27
+ add_default_name_and_field(options)
28
28
  end
29
29
 
30
30
  include_hidden = options.delete("include_hidden") { true }
@@ -7,7 +7,7 @@ module ActionView
7
7
  def render
8
8
  include_hidden = @options.delete(:include_hidden)
9
9
  options = @options.stringify_keys
10
- add_default_name_and_id(options)
10
+ add_default_name_and_field(options)
11
11
 
12
12
  if options["multiple"] && include_hidden
13
13
  hidden_field_for_multiple_file(options) + super
@@ -48,18 +48,11 @@ module ActionView
48
48
  def render(&block)
49
49
  options = @options.stringify_keys
50
50
  tag_value = options.delete("value")
51
- name_and_id = options.dup
52
51
 
53
- if name_and_id["for"]
54
- name_and_id["id"] = name_and_id["for"]
55
- else
56
- name_and_id.delete("id")
57
- end
58
-
59
- add_default_name_and_id_for_value(tag_value, name_and_id)
52
+ add_default_name_and_field_for_value(tag_value, options, "for")
60
53
  options.delete("index")
54
+ options.delete("name")
61
55
  options.delete("namespace")
62
- options["for"] = name_and_id["id"] unless options.key?("for")
63
56
 
64
57
  builder = LabelBuilder.new(@template_object, @object_name, @method_name, @object, tag_value)
65
58
 
@@ -71,7 +64,7 @@ module ActionView
71
64
  render_component(builder)
72
65
  end
73
66
 
74
- label_tag(name_and_id["id"], content, options)
67
+ label_tag(options["for"], content, options)
75
68
  end
76
69
 
77
70
  private
@@ -18,7 +18,7 @@ module ActionView
18
18
  options["type"] = "radio"
19
19
  options["value"] = @tag_value
20
20
  options["checked"] = "checked" if input_checked?(options)
21
- add_default_name_and_id_for_value(@tag_value, options)
21
+ add_default_name_and_field_for_value(@tag_value, options)
22
22
  tag("input", options)
23
23
  end
24
24
 
@@ -11,7 +11,7 @@ module ActionView
11
11
  html_options[prop.to_s] = options.delete(prop) if options.key?(prop) && !html_options.key?(prop.to_s)
12
12
  end
13
13
 
14
- add_default_name_and_id(html_options)
14
+ add_default_name_and_field(html_options)
15
15
 
16
16
  if placeholder_required?(html_options)
17
17
  raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
@@ -10,7 +10,7 @@ module ActionView
10
10
 
11
11
  def render
12
12
  options = @options.stringify_keys
13
- add_default_name_and_id(options)
13
+ add_default_name_and_field(options)
14
14
 
15
15
  if size = options.delete("size")
16
16
  options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
@@ -13,7 +13,7 @@ module ActionView
13
13
  options["size"] = options["maxlength"] unless options.key?("size")
14
14
  options["type"] ||= field_type
15
15
  options["value"] = options.fetch("value") { value_before_type_cast } unless field_type == "file"
16
- add_default_name_and_id(options)
16
+ add_default_name_and_field(options)
17
17
  tag("input", options)
18
18
  end
19
19
 
@@ -260,7 +260,14 @@ module ActionView
260
260
  prefix, first_part = cut_excerpt_part(:first, first_part, separator, options)
261
261
  postfix, second_part = cut_excerpt_part(:second, second_part, separator, options)
262
262
 
263
- affix = [first_part, separator, phrase, separator, second_part].join.strip
263
+ affix = [
264
+ first_part,
265
+ !first_part.empty? ? separator : "",
266
+ phrase,
267
+ !second_part.empty? ? separator : "",
268
+ second_part
269
+ ].join.strip
270
+
264
271
  [prefix, affix, postfix].join
265
272
  end
266
273
 
@@ -271,7 +278,7 @@ module ActionView
271
278
  #
272
279
  # The word will be pluralized using rules defined for the locale
273
280
  # (you must define your own inflection rules for languages other than English).
274
- # See ActiveSupport::Inflector.pluralize
281
+ # See ActiveSupport::Inflector.pluralize.
275
282
  #
276
283
  # pluralize(1, 'person')
277
284
  # # => "1 person"
@@ -346,7 +353,7 @@ module ActionView
346
353
  # ==== Options
347
354
  # * <tt>:sanitize</tt> - If +false+, does not sanitize +text+.
348
355
  # * <tt>:sanitize_options</tt> - Any extra options you want appended to the sanitize.
349
- # * <tt>:wrapper_tag</tt> - String representing the wrapper tag, defaults to <tt>"p"</tt>
356
+ # * <tt>:wrapper_tag</tt> - String representing the wrapper tag, defaults to <tt>"p"</tt>.
350
357
  #
351
358
  # ==== Examples
352
359
  # my_text = "Here is some basic text...\n...with a line break."
@@ -25,6 +25,13 @@ module ActionView
25
25
  self
26
26
  end
27
27
 
28
+ # Returns the complete body as a string.
29
+ def body
30
+ buffer = String.new
31
+ each { |part| buffer << part }
32
+ buffer
33
+ end
34
+
28
35
  private
29
36
  # This is the same logging logic as in ShowExceptions middleware.
30
37
  def log_error(exception)
@@ -42,7 +49,7 @@ module ActionView
42
49
  # object that responds to each. This object is initialized with a block
43
50
  # that knows how to render the template.
44
51
  def render_template(view, template, layout_name = nil, locals = {}) # :nodoc:
45
- return [super.body] unless layout_name && template.supports_streaming?
52
+ return [super.body] unless template.supports_streaming?
46
53
 
47
54
  locals ||= {}
48
55
  layout = find_layout(layout_name, locals.keys, [formats.first])
@@ -18,7 +18,7 @@ module ActionView
18
18
  properties[:preamble] ||= ""
19
19
  properties[:postamble] ||= "#{properties[:bufvar]}"
20
20
 
21
- # Tell Eruby that whether template will be compiled with `frozen_string_literal: true`
21
+ # Tell Erubi whether the template will be compiled with `frozen_string_literal: true`
22
22
  properties[:freeze_template_literals] = !Template.frozen_string_literal
23
23
 
24
24
  properties[:escapefunc] = ""
@@ -20,6 +20,10 @@ module ActionView # :nodoc:
20
20
  def render(*args)
21
21
  ::File.read(@filename)
22
22
  end
23
+
24
+ def supports_streaming?
25
+ false
26
+ end
23
27
  end
24
28
  end
25
29
  end
@@ -301,7 +301,6 @@ module ActionView
301
301
  class RenderedViewContent < String # :nodoc:
302
302
  end
303
303
 
304
- # Need to experiment if this priority is the best one: rendered => output_buffer
305
304
  class RenderedViewsCollection
306
305
  def initialize
307
306
  @rendered_views ||= Hash.new { |hash, key| hash[key] = [] }
data/lib/action_view.rb CHANGED
@@ -81,6 +81,7 @@ module ActionView
81
81
  autoload :MissingTemplate
82
82
  autoload :ActionViewError
83
83
  autoload :EncodingError
84
+ autoload :StrictLocalsError
84
85
  autoload :TemplateError
85
86
  autoload :SyntaxErrorInTemplate
86
87
  autoload :WrongEncodingError
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionview
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.2.1
4
+ version: 8.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 8.0.2.1
18
+ version: 8.0.3
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 8.0.2.1
25
+ version: 8.0.3
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: builder
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -85,28 +85,28 @@ dependencies:
85
85
  requirements:
86
86
  - - '='
87
87
  - !ruby/object:Gem::Version
88
- version: 8.0.2.1
88
+ version: 8.0.3
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - '='
94
94
  - !ruby/object:Gem::Version
95
- version: 8.0.2.1
95
+ version: 8.0.3
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: activemodel
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - '='
101
101
  - !ruby/object:Gem::Version
102
- version: 8.0.2.1
102
+ version: 8.0.3
103
103
  type: :development
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - '='
108
108
  - !ruby/object:Gem::Version
109
- version: 8.0.2.1
109
+ version: 8.0.3
110
110
  description: Simple, battle-tested conventions and helpers for building web pages.
111
111
  email: david@loudthinking.com
112
112
  executables: []
@@ -246,10 +246,10 @@ licenses:
246
246
  - MIT
247
247
  metadata:
248
248
  bug_tracker_uri: https://github.com/rails/rails/issues
249
- changelog_uri: https://github.com/rails/rails/blob/v8.0.2.1/actionview/CHANGELOG.md
250
- documentation_uri: https://api.rubyonrails.org/v8.0.2.1/
249
+ changelog_uri: https://github.com/rails/rails/blob/v8.0.3/actionview/CHANGELOG.md
250
+ documentation_uri: https://api.rubyonrails.org/v8.0.3/
251
251
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
252
- source_code_uri: https://github.com/rails/rails/tree/v8.0.2.1/actionview
252
+ source_code_uri: https://github.com/rails/rails/tree/v8.0.3/actionview
253
253
  rubygems_mfa_required: 'true'
254
254
  rdoc_options: []
255
255
  require_paths: