actionview 6.1.3.2 → 7.0.0.alpha2

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +99 -262
  3. data/MIT-LICENSE +1 -1
  4. data/lib/action_view/base.rb +3 -3
  5. data/lib/action_view/buffers.rb +2 -2
  6. data/lib/action_view/cache_expiry.rb +46 -32
  7. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  8. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  9. data/lib/action_view/dependency_tracker.rb +6 -147
  10. data/lib/action_view/digestor.rb +7 -4
  11. data/lib/action_view/flows.rb +4 -4
  12. data/lib/action_view/gem_version.rb +4 -4
  13. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  14. data/lib/action_view/helpers/asset_tag_helper.rb +85 -30
  15. data/lib/action_view/helpers/asset_url_helper.rb +7 -7
  16. data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
  17. data/lib/action_view/helpers/cache_helper.rb +51 -3
  18. data/lib/action_view/helpers/capture_helper.rb +2 -2
  19. data/lib/action_view/helpers/controller_helper.rb +2 -2
  20. data/lib/action_view/helpers/csp_helper.rb +1 -1
  21. data/lib/action_view/helpers/csrf_helper.rb +1 -1
  22. data/lib/action_view/helpers/date_helper.rb +5 -5
  23. data/lib/action_view/helpers/debug_helper.rb +3 -1
  24. data/lib/action_view/helpers/form_helper.rb +72 -12
  25. data/lib/action_view/helpers/form_options_helper.rb +65 -33
  26. data/lib/action_view/helpers/form_tag_helper.rb +73 -30
  27. data/lib/action_view/helpers/javascript_helper.rb +3 -5
  28. data/lib/action_view/helpers/number_helper.rb +3 -4
  29. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  30. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  31. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  32. data/lib/action_view/helpers/tag_helper.rb +17 -4
  33. data/lib/action_view/helpers/tags/base.rb +2 -14
  34. data/lib/action_view/helpers/tags/check_box.rb +1 -1
  35. data/lib/action_view/helpers/tags/collection_select.rb +1 -1
  36. data/lib/action_view/helpers/tags/time_field.rb +10 -1
  37. data/lib/action_view/helpers/tags/weekday_select.rb +27 -0
  38. data/lib/action_view/helpers/tags.rb +3 -2
  39. data/lib/action_view/helpers/text_helper.rb +24 -13
  40. data/lib/action_view/helpers/translation_helper.rb +4 -3
  41. data/lib/action_view/helpers/url_helper.rb +122 -80
  42. data/lib/action_view/helpers.rb +25 -25
  43. data/lib/action_view/lookup_context.rb +33 -52
  44. data/lib/action_view/model_naming.rb +1 -1
  45. data/lib/action_view/path_set.rb +16 -22
  46. data/lib/action_view/railtie.rb +15 -2
  47. data/lib/action_view/render_parser.rb +188 -0
  48. data/lib/action_view/renderer/abstract_renderer.rb +2 -2
  49. data/lib/action_view/renderer/partial_renderer.rb +0 -34
  50. data/lib/action_view/renderer/renderer.rb +4 -4
  51. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
  52. data/lib/action_view/renderer/template_renderer.rb +6 -2
  53. data/lib/action_view/rendering.rb +2 -2
  54. data/lib/action_view/ripper_ast_parser.rb +198 -0
  55. data/lib/action_view/routing_url_for.rb +1 -1
  56. data/lib/action_view/template/error.rb +108 -13
  57. data/lib/action_view/template/handlers/erb.rb +6 -0
  58. data/lib/action_view/template/handlers.rb +3 -3
  59. data/lib/action_view/template/html.rb +3 -3
  60. data/lib/action_view/template/inline.rb +3 -3
  61. data/lib/action_view/template/raw_file.rb +3 -3
  62. data/lib/action_view/template/resolver.rb +84 -311
  63. data/lib/action_view/template/text.rb +3 -3
  64. data/lib/action_view/template/types.rb +14 -12
  65. data/lib/action_view/template.rb +10 -1
  66. data/lib/action_view/template_details.rb +66 -0
  67. data/lib/action_view/template_path.rb +64 -0
  68. data/lib/action_view/test_case.rb +6 -2
  69. data/lib/action_view/testing/resolvers.rb +11 -12
  70. data/lib/action_view/unbound_template.rb +33 -7
  71. data/lib/action_view.rb +3 -4
  72. data/lib/assets/compiled/rails-ujs.js +2 -2
  73. metadata +25 -18
@@ -4,7 +4,7 @@ require "active_support/core_ext/string/output_safety"
4
4
 
5
5
  module ActionView
6
6
  # = Action View Capture Helper
7
- module Helpers #:nodoc:
7
+ module Helpers # :nodoc:
8
8
  # CaptureHelper exposes methods to let you extract generated markup which
9
9
  # can be used in other parts of a template or layout file.
10
10
  #
@@ -198,7 +198,7 @@ module ActionView
198
198
 
199
199
  # Use an alternate output buffer for the duration of the block.
200
200
  # Defaults to a new empty string.
201
- def with_output_buffer(buf = nil) #:nodoc:
201
+ def with_output_buffer(buf = nil) # :nodoc:
202
202
  unless buf
203
203
  buf = ActionView::OutputBuffer.new
204
204
  if output_buffer && output_buffer.respond_to?(:encoding)
@@ -3,10 +3,10 @@
3
3
  require "active_support/core_ext/module/attr_internal"
4
4
 
5
5
  module ActionView
6
- module Helpers #:nodoc:
6
+ module Helpers # :nodoc:
7
7
  # This module keeps all methods and behavior in ActionView
8
8
  # that simply delegates to the controller.
9
- module ControllerHelper #:nodoc:
9
+ module ControllerHelper # :nodoc:
10
10
  attr_internal :controller, :request
11
11
 
12
12
  CONTROLLER_DELEGATES = [:request_forgery_protection_token, :params,
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActionView
4
4
  # = Action View CSP Helper
5
- module Helpers #:nodoc:
5
+ module Helpers # :nodoc:
6
6
  module CspHelper
7
7
  # Returns a meta tag "csp-nonce" with the per-session nonce value
8
8
  # for allowing inline <script> tags.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActionView
4
4
  # = Action View CSRF Helper
5
- module Helpers #:nodoc:
5
+ module Helpers # :nodoc:
6
6
  module CsrfHelper
7
7
  # Returns meta tags "csrf-param" and "csrf-token" with the name of the cross-site
8
8
  # request forgery protection parameter and token, respectively.
@@ -9,7 +9,7 @@ require "active_support/core_ext/object/acts_like"
9
9
  require "active_support/core_ext/object/with_options"
10
10
 
11
11
  module ActionView
12
- module Helpers #:nodoc:
12
+ module Helpers # :nodoc:
13
13
  # = Action View Date Helpers
14
14
  #
15
15
  # The Date Helper primarily creates select/option tags for different kinds of dates and times or date and time
@@ -140,7 +140,7 @@ module ActionView
140
140
  minute_offset_for_leap_year = leap_years * 1440
141
141
  # Discount the leap year days when calculating year distance.
142
142
  # e.g. if there are 20 leap year days between 2 dates having the same day
143
- # and month then the based on 365 days calculation
143
+ # and month then based on 365 days calculation
144
144
  # the distance in years will come out to over 80 years when in written
145
145
  # English it would read better as about 80 years.
146
146
  minutes_with_offset = distance_in_minutes - minute_offset_for_leap_year
@@ -699,7 +699,7 @@ module ActionView
699
699
  end
700
700
  end
701
701
 
702
- class DateTimeSelector #:nodoc:
702
+ class DateTimeSelector # :nodoc:
703
703
  include ActionView::Helpers::TagHelper
704
704
 
705
705
  DEFAULT_PREFIX = "date"
@@ -1060,7 +1060,7 @@ module ActionView
1060
1060
  (content_tag("select", select_html.html_safe, select_options) + "\n").html_safe
1061
1061
  end
1062
1062
 
1063
- # Builds the css class value for the select element
1063
+ # Builds the CSS class value for the select element
1064
1064
  # css_class_attribute(:year, 'date optional', { year: 'my-year' })
1065
1065
  # => "date optional my-year"
1066
1066
  def css_class_attribute(type, html_options_class, options) # :nodoc:
@@ -1125,7 +1125,7 @@ module ActionView
1125
1125
  # Returns the id attribute for the input tag.
1126
1126
  # => "post_written_on_1i"
1127
1127
  def input_id_from_type(type)
1128
- id = input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, "_").gsub(/[\]\)]/, "")
1128
+ id = input_name_from_type(type).gsub(/([\[(])|(\]\[)/, "_").gsub(/[\])]/, "")
1129
1129
  id = @options[:namespace] + "_" + id if @options[:namespace]
1130
1130
 
1131
1131
  id
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "action_view/helpers/tag_helper"
4
+
3
5
  module ActionView
4
6
  # = Action View Debug Helper
5
7
  #
6
8
  # Provides a set of methods for making it easier to debug Rails objects.
7
- module Helpers #:nodoc:
9
+ module Helpers # :nodoc:
8
10
  module DebugHelper
9
11
  include TagHelper
10
12
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "cgi"
4
4
  require "action_view/helpers/date_helper"
5
- require "action_view/helpers/tag_helper"
5
+ require "action_view/helpers/url_helper"
6
6
  require "action_view/helpers/form_tag_helper"
7
7
  require "action_view/helpers/active_model_helper"
8
8
  require "action_view/model_naming"
@@ -11,11 +11,10 @@ require "active_support/core_ext/module/attribute_accessors"
11
11
  require "active_support/core_ext/hash/slice"
12
12
  require "active_support/core_ext/string/output_safety"
13
13
  require "active_support/core_ext/string/inflections"
14
- require "active_support/core_ext/symbol/starts_ends_with"
15
14
 
16
15
  module ActionView
17
16
  # = Action View Form Helpers
18
- module Helpers #:nodoc:
17
+ module Helpers # :nodoc:
19
18
  # Form helpers are designed to make working with resources much easier
20
19
  # compared to using vanilla HTML.
21
20
  #
@@ -454,7 +453,7 @@ module ActionView
454
453
  form_tag_with_body(html_options, output)
455
454
  end
456
455
 
457
- def apply_form_for_options!(record, object, options) #:nodoc:
456
+ def apply_form_for_options!(record, object, options) # :nodoc:
458
457
  object = convert_to_model(object)
459
458
 
460
459
  as = options[:as]
@@ -604,10 +603,16 @@ module ActionView
604
603
  # This is helpful when fragment-caching the form. Remote forms
605
604
  # get the authenticity token from the <tt>meta</tt> tag, so embedding is
606
605
  # unnecessary unless you support browsers without JavaScript.
607
- # * <tt>:local</tt> - By default form submits via typical HTTP requests.
608
- # Enable remote and unobtrusive XHRs submits with <tt>local: false</tt>.
609
- # Remote forms may be enabled by default by setting
610
- # <tt>config.action_view.form_with_generates_remote_forms = true</tt>.
606
+ # * <tt>:local</tt> - Whether to use standard HTTP form submission.
607
+ # When set to <tt>true</tt>, the form is submitted via standard HTTP.
608
+ # When set to <tt>false</tt>, the form is submitted as a "remote form", which
609
+ # is handled by Rails UJS as an XHR. When unspecified, the behavior is derived
610
+ # from <tt>config.action_view.form_with_generates_remote_forms</tt> where the
611
+ # config's value is actually the inverse of what <tt>local</tt>'s value would be.
612
+ # As of Rails 6.1, that configuration option defaults to <tt>false</tt>
613
+ # (which has the equivalent effect of passing <tt>local: true</tt>).
614
+ # In previous versions of Rails, that configuration option defaults to
615
+ # <tt>true</tt> (the equivalent of passing <tt>local: false</tt>).
611
616
  # * <tt>:skip_enforcing_utf8</tt> - If set to true, a hidden input with name
612
617
  # utf8 is not output.
613
618
  # * <tt>:builder</tt> - Override the object used to build the form.
@@ -1403,8 +1408,9 @@ module ActionView
1403
1408
  # Returns a text_field of type "time".
1404
1409
  #
1405
1410
  # The default value is generated by trying to call +strftime+ with "%T.%L"
1406
- # on the object's value. It is still possible to override that
1407
- # by passing the "value" option.
1411
+ # on the object's value. If you pass <tt>include_seconds: false</tt>, it will be
1412
+ # formatted by trying to call +strftime+ with "%H:%M" on the object's value.
1413
+ # It is also possible to override this by passing the "value" option.
1408
1414
  #
1409
1415
  # === Options
1410
1416
  # * Accepts same options as time_field_tag
@@ -1425,6 +1431,12 @@ module ActionView
1425
1431
  # time_field("task", "started_at", min: "01:00:00")
1426
1432
  # # => <input id="task_started_at" name="task[started_at]" type="time" min="01:00:00.000" />
1427
1433
  #
1434
+ # By default, provided times will be formatted including seconds. You can render just the hour
1435
+ # and minute by passing <tt>include_seconds: false</tt>. Some browsers will render a simpler UI
1436
+ # if you exclude seconds in the timestamp format.
1437
+ #
1438
+ # time_field("task", "started_at", value: Time.now, include_seconds: false)
1439
+ # # => <input id="task_started_at" name="task[started_at]" type="time" value="01:00" />
1428
1440
  def time_field(object_name, method, options = {})
1429
1441
  Tags::TimeField.new(object_name, method, self, options).render
1430
1442
  end
@@ -1685,6 +1697,47 @@ module ActionView
1685
1697
  @index = options[:index] || options[:child_index]
1686
1698
  end
1687
1699
 
1700
+ # Generate an HTML <tt>id</tt> attribute value.
1701
+ #
1702
+ # return the <tt><form></tt> element's <tt>id</tt> attribute.
1703
+ #
1704
+ # <%= form_for @post do |f| %>
1705
+ # <%# ... %>
1706
+ #
1707
+ # <% content_for :sticky_footer do %>
1708
+ # <%= form.button(form: f.id) %>
1709
+ # <% end %>
1710
+ # <% end %>
1711
+ #
1712
+ # In the example above, the <tt>:sticky_footer</tt> content area will
1713
+ # exist outside of the <tt><form></tt> element. By declaring the
1714
+ # <tt>form</tt> HTML attribute, we hint to the browser that the generated
1715
+ # <tt><button></tt> element should be treated as the <tt><form></tt>
1716
+ # element's submit button, regardless of where it exists in the DOM.
1717
+ def id
1718
+ options.dig(:html, :id)
1719
+ end
1720
+
1721
+ # Generate an HTML <tt>id</tt> attribute value for the given field
1722
+ #
1723
+ # Return the value generated by the <tt>FormBuilder</tt> for the given
1724
+ # attribute name.
1725
+ #
1726
+ # <%= form_for @post do |f| %>
1727
+ # <%= f.label :title %>
1728
+ # <%= f.text_field :title, aria: { describedby: f.field_id(:title, :error) } %>
1729
+ # <%= tag.span("is blank", id: f.field_id(:title, :error) %>
1730
+ # <% end %>
1731
+ #
1732
+ # In the example above, the <tt><input type="text"></tt> element built by
1733
+ # the call to <tt>FormBuilder#text_field</tt> declares an
1734
+ # <tt>aria-describedby</tt> attribute referencing the <tt><span></tt>
1735
+ # element, sharing a common <tt>id</tt> root (<tt>post_title</tt>, in this
1736
+ # case).
1737
+ def field_id(method, *suffixes, index: @index)
1738
+ @template.field_id(@object_name, method, *suffixes, index: index)
1739
+ end
1740
+
1688
1741
  ##
1689
1742
  # :method: text_field
1690
1743
  #
@@ -2386,7 +2439,7 @@ module ActionView
2386
2439
  # hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
2387
2440
  # shown.
2388
2441
  #
2389
- # Using this method inside a +form_for+ block will set the enclosing form's encoding to <tt>multipart/form-data</tt>.
2442
+ # Using this method inside a +form_with+ block will set the enclosing form's encoding to <tt>multipart/form-data</tt>.
2390
2443
  #
2391
2444
  # ==== Options
2392
2445
  # * Creates standard HTML attributes for the tag.
@@ -2505,6 +2558,11 @@ module ActionView
2505
2558
  value = @template.capture { yield(value) }
2506
2559
  end
2507
2560
 
2561
+ formmethod = options[:formmethod]
2562
+ if formmethod.present? && !/post|get/i.match?(formmethod) && !options.key?(:name) && !options.key?(:value)
2563
+ options.merge! formmethod: :post, name: "_method", value: formmethod
2564
+ end
2565
+
2508
2566
  @template.button_tag(value, options)
2509
2567
  end
2510
2568
 
@@ -2565,7 +2623,9 @@ module ActionView
2565
2623
  else
2566
2624
  options[:child_index] = nested_child_index(name)
2567
2625
  end
2568
- output << fields_for_nested_model("#{name}[#{options[:child_index]}]", child, options, block)
2626
+ if content = fields_for_nested_model("#{name}[#{options[:child_index]}]", child, options, block)
2627
+ output << content
2628
+ end
2569
2629
  end
2570
2630
  output
2571
2631
  elsif association
@@ -2,21 +2,21 @@
2
2
 
3
3
  require "cgi"
4
4
  require "erb"
5
- require "action_view/helpers/form_helper"
6
5
  require "active_support/core_ext/string/output_safety"
7
6
  require "active_support/core_ext/array/extract_options"
8
7
  require "active_support/core_ext/array/wrap"
8
+ require "action_view/helpers/text_helper"
9
9
 
10
10
  module ActionView
11
11
  # = Action View Form Option Helpers
12
- module Helpers #:nodoc:
12
+ module Helpers # :nodoc:
13
13
  # Provides a number of methods for turning different kinds of containers into a set of option tags.
14
14
  #
15
15
  # The <tt>collection_select</tt>, <tt>select</tt> and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter, a hash:
16
16
  #
17
17
  # * <tt>:include_blank</tt> - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
18
18
  #
19
- # select("post", "category", Post::CATEGORIES, { include_blank: true })
19
+ # select(:post, :category, Post::CATEGORIES, { include_blank: true })
20
20
  #
21
21
  # could become:
22
22
  #
@@ -30,7 +30,7 @@ module ActionView
30
30
  #
31
31
  # Example with <tt>@post.person_id => 2</tt>:
32
32
  #
33
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: 'None' })
33
+ # select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: "None" })
34
34
  #
35
35
  # could become:
36
36
  #
@@ -43,7 +43,7 @@ module ActionView
43
43
  #
44
44
  # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this prepends an option with a generic prompt -- "Please select" -- or the given prompt string.
45
45
  #
46
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { prompt: 'Select Person' })
46
+ # select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { prompt: "Select Person" })
47
47
  #
48
48
  # could become:
49
49
  #
@@ -54,10 +54,10 @@ module ActionView
54
54
  # <option value="3">Rafael</option>
55
55
  # </select>
56
56
  #
57
- # * <tt>:index</tt> - like the other form helpers, +select+ can accept an <tt>:index</tt> option to manually set the ID used in the resulting output. Unlike other helpers, +select+ expects this
57
+ # * <tt>:index</tt> - like the other form helpers, <tt>select</tt> can accept an <tt>:index</tt> option to manually set the ID used in the resulting output. Unlike other helpers, <tt>select</tt> expects this
58
58
  # option to be in the +html_options+ parameter.
59
59
  #
60
- # select("album[]", "genre", %w[rap rock country], {}, { index: nil })
60
+ # select("album[]", :genre, %w[ rap rock country ], {}, { index: nil })
61
61
  #
62
62
  # becomes:
63
63
  #
@@ -69,7 +69,7 @@ module ActionView
69
69
  #
70
70
  # * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
71
71
  #
72
- # select("post", "category", Post::CATEGORIES, { disabled: 'restricted' })
72
+ # select(:post, :category, Post::CATEGORIES, { disabled: "restricted" })
73
73
  #
74
74
  # could become:
75
75
  #
@@ -90,7 +90,6 @@ module ActionView
90
90
  # <option value="3">Jokes</option>
91
91
  # <option value="4">Poems</option>
92
92
  # </select>
93
- #
94
93
  module FormOptionsHelper
95
94
  # ERB::Util can mask some helpers like textilize. Make sure to include them.
96
95
  include TextHelper
@@ -100,25 +99,22 @@ module ActionView
100
99
  #
101
100
  # There are two possible formats for the +choices+ parameter, corresponding to other helpers' output:
102
101
  #
103
- # * A flat collection (see +options_for_select+).
104
- #
105
- # * A nested collection (see +grouped_options_for_select+).
102
+ # * A flat collection (see <tt>options_for_select</tt>).
103
+ # * A nested collection (see <tt>grouped_options_for_select</tt>).
106
104
  #
107
- # For example:
105
+ # Example with <tt>@post.person_id => 2</tt>:
108
106
  #
109
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
107
+ # select :post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
110
108
  #
111
109
  # would become:
112
110
  #
113
111
  # <select name="post[person_id]" id="post_person_id">
114
112
  # <option value="" label=" "></option>
115
- # <option value="1" selected="selected">David</option>
116
- # <option value="2">Eileen</option>
113
+ # <option value="1">David</option>
114
+ # <option value="2" selected="selected">Eileen</option>
117
115
  # <option value="3">Rafael</option>
118
116
  # </select>
119
117
  #
120
- # assuming the associated person has ID 1.
121
- #
122
118
  # This can be used to provide a default set of options in the standard way: before rendering the create form, a
123
119
  # new model instance is assigned the default options and bound to @model_name. Usually this model is not saved
124
120
  # to the database. Instead, a second model object is created when the create request is received.
@@ -132,9 +128,9 @@ module ActionView
132
128
  # A block can be passed to +select+ to customize how the options tags will be rendered. This
133
129
  # is useful when the options tag has complex attributes.
134
130
  #
135
- # select(report, "campaign_ids") do
131
+ # select(report, :campaign_ids) do
136
132
  # available_campaigns.each do |c|
137
- # content_tag(:option, c.name, value: c.id, data: { tags: c.tags.to_json })
133
+ # tag.option(c.name, value: c.id, data: { tags: c.tags.to_json })
138
134
  # end
139
135
  # end
140
136
  #
@@ -159,7 +155,6 @@ module ActionView
159
155
  #
160
156
  # In case if you don't want the helper to generate this hidden field you can specify
161
157
  # <tt>include_hidden: false</tt> option.
162
- #
163
158
  def select(object, method, choices = nil, options = {}, html_options = {}, &block)
164
159
  Tags::Select.new(object, method, self, choices, options, html_options, &block).render
165
160
  end
@@ -183,6 +178,7 @@ module ActionView
183
178
  #
184
179
  # class Author < ActiveRecord::Base
185
180
  # has_many :posts
181
+ #
186
182
  # def name_with_initial
187
183
  # "#{first_name.first}. #{last_name}"
188
184
  # end
@@ -227,19 +223,19 @@ module ActionView
227
223
  #
228
224
  # Example object structure for use with this method:
229
225
  #
226
+ # # attributes: id, name
230
227
  # class Continent < ActiveRecord::Base
231
228
  # has_many :countries
232
- # # attribs: id, name
233
229
  # end
234
230
  #
231
+ # # attributes: id, name, continent_id
235
232
  # class Country < ActiveRecord::Base
236
233
  # belongs_to :continent
237
- # # attribs: id, name, continent_id
238
234
  # end
239
235
  #
236
+ # # attributes: id, name, country_id
240
237
  # class City < ActiveRecord::Base
241
238
  # belongs_to :country
242
- # # attribs: id, name, country_id
243
239
  # end
244
240
  #
245
241
  # Sample usage:
@@ -258,7 +254,6 @@ module ActionView
258
254
  # <option value="2">Ireland</option>
259
255
  # </optgroup>
260
256
  # </select>
261
- #
262
257
  def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
263
258
  Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render
264
259
  end
@@ -282,21 +277,27 @@ module ActionView
282
277
  # Finally, this method supports a <tt>:default</tt> option, which selects
283
278
  # a default ActiveSupport::TimeZone if the object's time zone is +nil+.
284
279
  #
285
- # time_zone_select("user", "time_zone", nil, include_blank: true)
280
+ # time_zone_select(:user, :time_zone, nil, include_blank: true)
286
281
  #
287
- # time_zone_select("user", "time_zone", nil, default: "Pacific Time (US & Canada)")
282
+ # time_zone_select(:user, :time_zone, nil, default: "Pacific Time (US & Canada)")
288
283
  #
289
- # time_zone_select("user", 'time_zone', ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
284
+ # time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
290
285
  #
291
- # time_zone_select("user", 'time_zone', [ ActiveSupport::TimeZone['Alaska'], ActiveSupport::TimeZone['Hawaii'] ])
286
+ # time_zone_select(:user, :time_zone, [ ActiveSupport::TimeZone["Alaska"], ActiveSupport::TimeZone["Hawaii"] ])
292
287
  #
293
- # time_zone_select("user", 'time_zone', /Australia/)
288
+ # time_zone_select(:user, :time_zone, /Australia/)
294
289
  #
295
- # time_zone_select("user", "time_zone", ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
290
+ # time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
296
291
  def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
297
292
  Tags::TimeZoneSelect.new(object, method, self, priority_zones, options, html_options).render
298
293
  end
299
294
 
295
+ # Returns select and option tags for the given object and method, using
296
+ # <tt>weekday_options_for_select</tt> to generate the list of option tags.
297
+ def weekday_select(object, method, options = {}, html_options = {}, &block)
298
+ Tags::WeekdaySelect.new(object, method, self, options, html_options, &block).render
299
+ end
300
+
300
301
  # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
301
302
  # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
302
303
  # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
@@ -593,6 +594,22 @@ module ActionView
593
594
  zone_options.safe_concat options_for_select(convert_zones[zones], selected)
594
595
  end
595
596
 
597
+ # Returns a string of option tags for the days of the week.
598
+ #
599
+ # Options:
600
+ # * <tt>:index_as_value</tt> - Defaults to false, set to true to use the index of the weekday as the value.
601
+ # * <tt>:day_format</tt> - The I18n key of the array to use for the weekday options.
602
+ # Defaults to :day_names, set to :abbr_day_names for abbreviations.
603
+ #
604
+ # NOTE: Only the option tags are returned, you have to wrap this call in
605
+ # a regular HTML select tag.
606
+ def weekday_options_for_select(selected = nil, index_as_value: false, day_format: :day_names)
607
+ day_names = I18n.translate("date.#{day_format}")
608
+ day_names = day_names.map.with_index.to_h if index_as_value
609
+
610
+ options_for_select(day_names, selected)
611
+ end
612
+
596
613
  # Returns radio button tags for the collection of existing return values
597
614
  # of +method+ for +object+'s class. The value returned from calling
598
615
  # +method+ on the instance +object+ will be selected. If calling +method+
@@ -606,11 +623,14 @@ module ActionView
606
623
  # retrieve the value/text.
607
624
  #
608
625
  # Example object structure for use with this method:
626
+ #
609
627
  # class Post < ActiveRecord::Base
610
628
  # belongs_to :author
611
629
  # end
630
+ #
612
631
  # class Author < ActiveRecord::Base
613
632
  # has_many :posts
633
+ #
614
634
  # def name_with_initial
615
635
  # "#{first_name.first}. #{last_name}"
616
636
  # end
@@ -793,9 +813,9 @@ module ActionView
793
813
 
794
814
  def extract_values_from_collection(collection, value_method, selected)
795
815
  if selected.is_a?(Proc)
796
- collection.map do |element|
816
+ collection.filter_map do |element|
797
817
  element.public_send(value_method) if selected.call(element)
798
- end.compact
818
+ end
799
819
  else
800
820
  selected
801
821
  end
@@ -859,6 +879,18 @@ module ActionView
859
879
  @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_html_options.merge(html_options))
860
880
  end
861
881
 
882
+ # Wraps ActionView::Helpers::FormOptionsHelper#weekday_select for form builders:
883
+ #
884
+ # <%= form_for @user do |f| %>
885
+ # <%= f.weekday_select :weekday, include_blank: true %>
886
+ # <%= f.submit %>
887
+ # <% end %>
888
+ #
889
+ # Please refer to the documentation of the base helper for details.
890
+ def weekday_select(method, options = {}, html_options = {})
891
+ @template.weekday_select(@object_name, method, objectify_options(options), @default_html_options.merge(html_options))
892
+ end
893
+
862
894
  # Wraps ActionView::Helpers::FormOptionsHelper#collection_check_boxes for form builders:
863
895
  #
864
896
  # <%= form_for @post do |f| %>