actionview 4.2.11.1 → 7.0.2.4
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.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +229 -215
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +116 -43
- data/lib/action_view/buffers.rb +20 -3
- data/lib/action_view/cache_expiry.rb +66 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +21 -122
- data/lib/action_view/digestor.rb +92 -85
- data/lib/action_view/flows.rb +15 -16
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +17 -12
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -101
- data/lib/action_view/helpers/asset_url_helper.rb +180 -74
- data/lib/action_view/helpers/atom_feed_helper.rb +21 -19
- data/lib/action_view/helpers/cache_helper.rb +156 -43
- data/lib/action_view/helpers/capture_helper.rb +21 -14
- data/lib/action_view/helpers/controller_helper.rb +16 -5
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +288 -132
- data/lib/action_view/helpers/debug_helper.rb +9 -6
- data/lib/action_view/helpers/form_helper.rb +956 -173
- data/lib/action_view/helpers/form_options_helper.rb +178 -97
- data/lib/action_view/helpers/form_tag_helper.rb +220 -101
- data/lib/action_view/helpers/javascript_helper.rb +33 -19
- data/lib/action_view/helpers/number_helper.rb +88 -63
- data/lib/action_view/helpers/output_safety_helper.rb +38 -6
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +31 -32
- data/lib/action_view/helpers/tag_helper.rb +332 -71
- data/lib/action_view/helpers/tags/base.rb +123 -99
- data/lib/action_view/helpers/tags/check_box.rb +21 -20
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +5 -3
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +18 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +6 -0
- data/lib/action_view/helpers/tags/label.rb +7 -2
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +12 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +5 -2
- data/lib/action_view/helpers/text_helper.rb +80 -51
- data/lib/action_view/helpers/translation_helper.rb +120 -69
- data/lib/action_view/helpers/url_helper.rb +398 -171
- data/lib/action_view/helpers.rb +29 -27
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +137 -113
- data/lib/action_view/model_naming.rb +4 -2
- data/lib/action_view/path_set.rb +28 -32
- data/lib/action_view/railtie.rb +74 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +152 -15
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +51 -333
- data/lib/action_view/renderer/renderer.rb +68 -11
- data/lib/action_view/renderer/streaming_template_renderer.rb +60 -56
- data/lib/action_view/renderer/template_renderer.rb +87 -74
- data/lib/action_view/rendering.rb +73 -47
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +35 -24
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +151 -41
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +29 -89
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +14 -10
- data/lib/action_view/template/html.rb +12 -13
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +139 -300
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +10 -12
- data/lib/action_view/template/types.rb +28 -26
- data/lib/action_view/template.rb +123 -91
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +70 -53
- data/lib/action_view/testing/resolvers.rb +25 -35
- data/lib/action_view/unbound_template.rb +57 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +16 -11
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +52 -32
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,61 +1,63 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cgi"
|
4
|
+
require "erb"
|
5
|
+
require "active_support/core_ext/string/output_safety"
|
6
|
+
require "active_support/core_ext/array/extract_options"
|
7
|
+
require "active_support/core_ext/array/wrap"
|
8
|
+
require "action_view/helpers/text_helper"
|
7
9
|
|
8
10
|
module ActionView
|
9
11
|
# = Action View Form Option Helpers
|
10
|
-
module Helpers
|
12
|
+
module Helpers # :nodoc:
|
11
13
|
# Provides a number of methods for turning different kinds of containers into a set of option tags.
|
12
14
|
#
|
13
15
|
# The <tt>collection_select</tt>, <tt>select</tt> and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter, a hash:
|
14
16
|
#
|
15
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.
|
16
18
|
#
|
17
|
-
# select(
|
19
|
+
# select(:post, :category, Post::CATEGORIES, { include_blank: true })
|
18
20
|
#
|
19
21
|
# could become:
|
20
22
|
#
|
21
|
-
# <select name="post[category]">
|
22
|
-
# <option></option>
|
23
|
-
# <option>joke</option>
|
24
|
-
# <option>poem</option>
|
23
|
+
# <select name="post[category]" id="post_category">
|
24
|
+
# <option value="" label=" "></option>
|
25
|
+
# <option value="joke">joke</option>
|
26
|
+
# <option value="poem">poem</option>
|
25
27
|
# </select>
|
26
28
|
#
|
27
29
|
# Another common case is a select tag for a <tt>belongs_to</tt>-associated object.
|
28
30
|
#
|
29
31
|
# Example with <tt>@post.person_id => 2</tt>:
|
30
32
|
#
|
31
|
-
# select(
|
33
|
+
# select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: "None" })
|
32
34
|
#
|
33
35
|
# could become:
|
34
36
|
#
|
35
|
-
# <select name="post[person_id]">
|
37
|
+
# <select name="post[person_id]" id="post_person_id">
|
36
38
|
# <option value="">None</option>
|
37
39
|
# <option value="1">David</option>
|
38
|
-
# <option value="2" selected="selected">
|
39
|
-
# <option value="3">
|
40
|
+
# <option value="2" selected="selected">Eileen</option>
|
41
|
+
# <option value="3">Rafael</option>
|
40
42
|
# </select>
|
41
43
|
#
|
42
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.
|
43
45
|
#
|
44
|
-
# select(
|
46
|
+
# select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { prompt: "Select Person" })
|
45
47
|
#
|
46
48
|
# could become:
|
47
49
|
#
|
48
|
-
# <select name="post[person_id]">
|
50
|
+
# <select name="post[person_id]" id="post_person_id">
|
49
51
|
# <option value="">Select Person</option>
|
50
52
|
# <option value="1">David</option>
|
51
|
-
# <option value="2">
|
52
|
-
# <option value="3">
|
53
|
+
# <option value="2">Eileen</option>
|
54
|
+
# <option value="3">Rafael</option>
|
53
55
|
# </select>
|
54
56
|
#
|
55
|
-
# * <tt>:index</tt> - like the other form helpers,
|
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
|
56
58
|
# option to be in the +html_options+ parameter.
|
57
59
|
#
|
58
|
-
# select("album[]",
|
60
|
+
# select("album[]", :genre, %w[ rap rock country ], {}, { index: nil })
|
59
61
|
#
|
60
62
|
# becomes:
|
61
63
|
#
|
@@ -67,29 +69,27 @@ module ActionView
|
|
67
69
|
#
|
68
70
|
# * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
|
69
71
|
#
|
70
|
-
# select(
|
72
|
+
# select(:post, :category, Post::CATEGORIES, { disabled: "restricted" })
|
71
73
|
#
|
72
74
|
# could become:
|
73
75
|
#
|
74
|
-
# <select name="post[category]">
|
75
|
-
# <option
|
76
|
-
# <option>
|
77
|
-
# <option>
|
78
|
-
# <option disabled="disabled">restricted</option>
|
76
|
+
# <select name="post[category]" id="post_category">
|
77
|
+
# <option value="joke">joke</option>
|
78
|
+
# <option value="poem">poem</option>
|
79
|
+
# <option disabled="disabled" value="restricted">restricted</option>
|
79
80
|
# </select>
|
80
81
|
#
|
81
82
|
# When used with the <tt>collection_select</tt> helper, <tt>:disabled</tt> can also be a Proc that identifies those options that should be disabled.
|
82
83
|
#
|
83
|
-
# collection_select(:post, :category_id, Category.all, :id, :name, {disabled:
|
84
|
+
# collection_select(:post, :category_id, Category.all, :id, :name, { disabled: -> (category) { category.archived? } })
|
84
85
|
#
|
85
86
|
# If the categories "2008 stuff" and "Christmas" return true when the method <tt>archived?</tt> is called, this would return:
|
86
|
-
# <select name="post[category_id]">
|
87
|
+
# <select name="post[category_id]" id="post_category_id">
|
87
88
|
# <option value="1" disabled="disabled">2008 stuff</option>
|
88
89
|
# <option value="2" disabled="disabled">Christmas</option>
|
89
90
|
# <option value="3">Jokes</option>
|
90
91
|
# <option value="4">Poems</option>
|
91
92
|
# </select>
|
92
|
-
#
|
93
93
|
module FormOptionsHelper
|
94
94
|
# ERB::Util can mask some helpers like textilize. Make sure to include them.
|
95
95
|
include TextHelper
|
@@ -99,25 +99,22 @@ module ActionView
|
|
99
99
|
#
|
100
100
|
# There are two possible formats for the +choices+ parameter, corresponding to other helpers' output:
|
101
101
|
#
|
102
|
-
# * A flat collection (see
|
102
|
+
# * A flat collection (see <tt>options_for_select</tt>).
|
103
|
+
# * A nested collection (see <tt>grouped_options_for_select</tt>).
|
103
104
|
#
|
104
|
-
#
|
105
|
+
# Example with <tt>@post.person_id => 2</tt>:
|
105
106
|
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
# 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 })
|
109
108
|
#
|
110
109
|
# would become:
|
111
110
|
#
|
112
|
-
# <select name="post[person_id]">
|
113
|
-
# <option value=""></option>
|
114
|
-
# <option value="1"
|
115
|
-
# <option value="2">
|
116
|
-
# <option value="3">
|
111
|
+
# <select name="post[person_id]" id="post_person_id">
|
112
|
+
# <option value="" label=" "></option>
|
113
|
+
# <option value="1">David</option>
|
114
|
+
# <option value="2" selected="selected">Eileen</option>
|
115
|
+
# <option value="3">Rafael</option>
|
117
116
|
# </select>
|
118
117
|
#
|
119
|
-
# assuming the associated person has ID 1.
|
120
|
-
#
|
121
118
|
# This can be used to provide a default set of options in the standard way: before rendering the create form, a
|
122
119
|
# new model instance is assigned the default options and bound to @model_name. Usually this model is not saved
|
123
120
|
# to the database. Instead, a second model object is created when the create request is received.
|
@@ -131,9 +128,9 @@ module ActionView
|
|
131
128
|
# A block can be passed to +select+ to customize how the options tags will be rendered. This
|
132
129
|
# is useful when the options tag has complex attributes.
|
133
130
|
#
|
134
|
-
# select(report,
|
131
|
+
# select(report, :campaign_ids) do
|
135
132
|
# available_campaigns.each do |c|
|
136
|
-
#
|
133
|
+
# tag.option(c.name, value: c.id, data: { tags: c.tags.to_json })
|
137
134
|
# end
|
138
135
|
# end
|
139
136
|
#
|
@@ -141,7 +138,7 @@ module ActionView
|
|
141
138
|
#
|
142
139
|
# The HTML specification says when +multiple+ parameter passed to select and all options got deselected
|
143
140
|
# web browsers do not send any value to server. Unfortunately this introduces a gotcha:
|
144
|
-
# if
|
141
|
+
# if a +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
|
145
142
|
# the user deselects all roles from +role_ids+ multiple select box, no +role_ids+ parameter is sent. So,
|
146
143
|
# any mass-assignment idiom like
|
147
144
|
#
|
@@ -158,7 +155,6 @@ module ActionView
|
|
158
155
|
#
|
159
156
|
# In case if you don't want the helper to generate this hidden field you can specify
|
160
157
|
# <tt>include_hidden: false</tt> option.
|
161
|
-
#
|
162
158
|
def select(object, method, choices = nil, options = {}, html_options = {}, &block)
|
163
159
|
Tags::Select.new(object, method, self, choices, options, html_options, &block).render
|
164
160
|
end
|
@@ -182,6 +178,7 @@ module ActionView
|
|
182
178
|
#
|
183
179
|
# class Author < ActiveRecord::Base
|
184
180
|
# has_many :posts
|
181
|
+
#
|
185
182
|
# def name_with_initial
|
186
183
|
# "#{first_name.first}. #{last_name}"
|
187
184
|
# end
|
@@ -192,7 +189,7 @@ module ActionView
|
|
192
189
|
# collection_select(:post, :author_id, Author.all, :id, :name_with_initial, prompt: true)
|
193
190
|
#
|
194
191
|
# If <tt>@post.author_id</tt> is already <tt>1</tt>, this would return:
|
195
|
-
# <select name="post[author_id]">
|
192
|
+
# <select name="post[author_id]" id="post_author_id">
|
196
193
|
# <option value="">Please select</option>
|
197
194
|
# <option value="1" selected="selected">D. Heinemeier Hansson</option>
|
198
195
|
# <option value="2">D. Thomas</option>
|
@@ -212,9 +209,13 @@ module ActionView
|
|
212
209
|
# * +method+ - The attribute of +object+ corresponding to the select tag
|
213
210
|
# * +collection+ - An array of objects representing the <tt><optgroup></tt> tags.
|
214
211
|
# * +group_method+ - The name of a method which, when called on a member of +collection+, returns an
|
215
|
-
# array of child objects representing the <tt><option></tt> tags.
|
212
|
+
# array of child objects representing the <tt><option></tt> tags. It can also be any object that responds
|
213
|
+
# to +call+, such as a +proc+, that will be called for each member of the +collection+ to retrieve the
|
214
|
+
# value.
|
216
215
|
# * +group_label_method+ - The name of a method which, when called on a member of +collection+, returns a
|
217
|
-
# string to be used as the +label+ attribute for its <tt><optgroup></tt> tag.
|
216
|
+
# string to be used as the +label+ attribute for its <tt><optgroup></tt> tag. It can also be any object
|
217
|
+
# that responds to +call+, such as a +proc+, that will be called for each member of the +collection+ to
|
218
|
+
# retrieve the label.
|
218
219
|
# * +option_key_method+ - The name of a method which, when called on a child object of a member of
|
219
220
|
# +collection+, returns a value to be used as the +value+ attribute for its <tt><option></tt> tag.
|
220
221
|
# * +option_value_method+ - The name of a method which, when called on a child object of a member of
|
@@ -222,19 +223,19 @@ module ActionView
|
|
222
223
|
#
|
223
224
|
# Example object structure for use with this method:
|
224
225
|
#
|
226
|
+
# # attributes: id, name
|
225
227
|
# class Continent < ActiveRecord::Base
|
226
228
|
# has_many :countries
|
227
|
-
# # attribs: id, name
|
228
229
|
# end
|
229
230
|
#
|
231
|
+
# # attributes: id, name, continent_id
|
230
232
|
# class Country < ActiveRecord::Base
|
231
233
|
# belongs_to :continent
|
232
|
-
# # attribs: id, name, continent_id
|
233
234
|
# end
|
234
235
|
#
|
236
|
+
# # attributes: id, name, country_id
|
235
237
|
# class City < ActiveRecord::Base
|
236
238
|
# belongs_to :country
|
237
|
-
# # attribs: id, name, country_id
|
238
239
|
# end
|
239
240
|
#
|
240
241
|
# Sample usage:
|
@@ -243,7 +244,7 @@ module ActionView
|
|
243
244
|
#
|
244
245
|
# Possible output:
|
245
246
|
#
|
246
|
-
# <select name="city[country_id]">
|
247
|
+
# <select name="city[country_id]" id="city_country_id">
|
247
248
|
# <optgroup label="Africa">
|
248
249
|
# <option value="1">South Africa</option>
|
249
250
|
# <option value="3">Somalia</option>
|
@@ -253,7 +254,6 @@ module ActionView
|
|
253
254
|
# <option value="2">Ireland</option>
|
254
255
|
# </optgroup>
|
255
256
|
# </select>
|
256
|
-
#
|
257
257
|
def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
|
258
258
|
Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render
|
259
259
|
end
|
@@ -268,29 +268,36 @@ module ActionView
|
|
268
268
|
# for more information.)
|
269
269
|
#
|
270
270
|
# You can also supply an array of ActiveSupport::TimeZone objects
|
271
|
-
# as +priority_zones
|
272
|
-
# (long) list.
|
273
|
-
#
|
274
|
-
#
|
271
|
+
# as +priority_zones+ so that they will be listed above the rest of the
|
272
|
+
# (long) list. You can use ActiveSupport::TimeZone.us_zones for a list
|
273
|
+
# of US time zones, ActiveSupport::TimeZone.country_zones(country_code)
|
274
|
+
# for another country's time zones, or a Regexp to select the zones of
|
275
|
+
# your choice.
|
275
276
|
#
|
276
277
|
# Finally, this method supports a <tt>:default</tt> option, which selects
|
277
278
|
# a default ActiveSupport::TimeZone if the object's time zone is +nil+.
|
278
279
|
#
|
279
|
-
# time_zone_select(
|
280
|
+
# time_zone_select(:user, :time_zone, nil, include_blank: true)
|
280
281
|
#
|
281
|
-
# time_zone_select(
|
282
|
+
# time_zone_select(:user, :time_zone, nil, default: "Pacific Time (US & Canada)")
|
282
283
|
#
|
283
|
-
# time_zone_select(
|
284
|
+
# time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
|
284
285
|
#
|
285
|
-
# time_zone_select(
|
286
|
+
# time_zone_select(:user, :time_zone, [ ActiveSupport::TimeZone["Alaska"], ActiveSupport::TimeZone["Hawaii"] ])
|
286
287
|
#
|
287
|
-
# time_zone_select(
|
288
|
+
# time_zone_select(:user, :time_zone, /Australia/)
|
288
289
|
#
|
289
|
-
# time_zone_select(
|
290
|
+
# time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
|
290
291
|
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
|
291
292
|
Tags::TimeZoneSelect.new(object, method, self, priority_zones, options, html_options).render
|
292
293
|
end
|
293
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
|
+
|
294
301
|
# Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
|
295
302
|
# where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
|
296
303
|
# the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
|
@@ -302,26 +309,26 @@ module ActionView
|
|
302
309
|
# # => <option value="DKK">Kroner</option>
|
303
310
|
#
|
304
311
|
# options_for_select([ "VISA", "MasterCard" ], "MasterCard")
|
305
|
-
# # => <option>VISA</option>
|
306
|
-
# # => <option selected="selected">MasterCard</option>
|
312
|
+
# # => <option value="VISA">VISA</option>
|
313
|
+
# # => <option selected="selected" value="MasterCard">MasterCard</option>
|
307
314
|
#
|
308
315
|
# options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
|
309
316
|
# # => <option value="$20">Basic</option>
|
310
317
|
# # => <option value="$40" selected="selected">Plus</option>
|
311
318
|
#
|
312
319
|
# options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
|
313
|
-
# # => <option selected="selected">VISA</option>
|
314
|
-
# # => <option>MasterCard</option>
|
315
|
-
# # => <option selected="selected">Discover</option>
|
320
|
+
# # => <option selected="selected" value="VISA">VISA</option>
|
321
|
+
# # => <option value="MasterCard">MasterCard</option>
|
322
|
+
# # => <option selected="selected" value="Discover">Discover</option>
|
316
323
|
#
|
317
324
|
# You can optionally provide HTML attributes as the last element of the array.
|
318
325
|
#
|
319
|
-
# options_for_select([ "Denmark", ["USA", {class: 'bold'}], "Sweden" ], ["USA", "Sweden"])
|
326
|
+
# options_for_select([ "Denmark", ["USA", { class: 'bold' }], "Sweden" ], ["USA", "Sweden"])
|
320
327
|
# # => <option value="Denmark">Denmark</option>
|
321
328
|
# # => <option value="USA" class="bold" selected="selected">USA</option>
|
322
329
|
# # => <option value="Sweden" selected="selected">Sweden</option>
|
323
330
|
#
|
324
|
-
# options_for_select([["Dollar", "$", {class: "bold"}], ["Kroner", "DKK", {onclick: "alert('HI');"}]])
|
331
|
+
# options_for_select([["Dollar", "$", { class: "bold" }], ["Kroner", "DKK", { onclick: "alert('HI');" }]])
|
325
332
|
# # => <option value="$" class="bold">Dollar</option>
|
326
333
|
# # => <option value="DKK" onclick="alert('HI');">Kroner</option>
|
327
334
|
#
|
@@ -351,18 +358,18 @@ module ActionView
|
|
351
358
|
return container if String === container
|
352
359
|
|
353
360
|
selected, disabled = extract_selected_and_disabled(selected).map do |r|
|
354
|
-
Array(r).map
|
361
|
+
Array(r).map(&:to_s)
|
355
362
|
end
|
356
363
|
|
357
364
|
container.map do |element|
|
358
365
|
html_attributes = option_html_attributes(element)
|
359
|
-
text, value = option_text_and_value(element).map
|
366
|
+
text, value = option_text_and_value(element).map(&:to_s)
|
360
367
|
|
361
368
|
html_attributes[:selected] ||= option_value_selected?(value, selected)
|
362
369
|
html_attributes[:disabled] ||= disabled && option_value_selected?(value, disabled)
|
363
370
|
html_attributes[:value] = value
|
364
371
|
|
365
|
-
content_tag_string(:option, text, html_attributes)
|
372
|
+
tag_builder.content_tag_string(:option, text, html_attributes)
|
366
373
|
end.join("\n").html_safe
|
367
374
|
end
|
368
375
|
|
@@ -454,9 +461,9 @@ module ActionView
|
|
454
461
|
def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
|
455
462
|
collection.map do |group|
|
456
463
|
option_tags = options_from_collection_for_select(
|
457
|
-
group
|
464
|
+
value_for_collection(group, group_method), option_key_method, option_value_method, selected_key)
|
458
465
|
|
459
|
-
content_tag(
|
466
|
+
content_tag("optgroup", option_tags, label: value_for_collection(group, group_label_method))
|
460
467
|
end.join.html_safe
|
461
468
|
end
|
462
469
|
|
@@ -528,7 +535,7 @@ module ActionView
|
|
528
535
|
body = "".html_safe
|
529
536
|
|
530
537
|
if prompt
|
531
|
-
body.safe_concat content_tag(
|
538
|
+
body.safe_concat content_tag("option", prompt_text(prompt), value: "")
|
532
539
|
end
|
533
540
|
|
534
541
|
grouped_options.each do |container|
|
@@ -541,14 +548,14 @@ module ActionView
|
|
541
548
|
end
|
542
549
|
|
543
550
|
html_attributes = { label: label }.merge!(html_attributes)
|
544
|
-
body.safe_concat content_tag(
|
551
|
+
body.safe_concat content_tag("optgroup", options_for_select(container, selected_key), html_attributes)
|
545
552
|
end
|
546
553
|
|
547
554
|
body
|
548
555
|
end
|
549
556
|
|
550
557
|
# Returns a string of option tags for pretty much any time zone in the
|
551
|
-
# world. Supply
|
558
|
+
# world. Supply an ActiveSupport::TimeZone name as +selected+ to have it
|
552
559
|
# marked as the selected option tag. You can also supply an array of
|
553
560
|
# ActiveSupport::TimeZone objects as +priority_zones+, so that they will
|
554
561
|
# be listed above the rest of the (long) list. (You can use
|
@@ -556,12 +563,13 @@ module ActionView
|
|
556
563
|
# of the US time zones, or a Regexp to select the zones of your choice)
|
557
564
|
#
|
558
565
|
# The +selected+ parameter must be either +nil+, or a string that names
|
559
|
-
#
|
566
|
+
# an ActiveSupport::TimeZone.
|
560
567
|
#
|
561
568
|
# By default, +model+ is the ActiveSupport::TimeZone constant (which can
|
562
|
-
# be obtained in Active Record as a value object). The
|
563
|
-
#
|
564
|
-
#
|
569
|
+
# be obtained in Active Record as a value object). The +model+ parameter
|
570
|
+
# must respond to +all+ and return an array of objects that represent time
|
571
|
+
# zones; each object must respond to +name+. If a Regexp is given it will
|
572
|
+
# attempt to match the zones using <code>match?</code> method.
|
565
573
|
#
|
566
574
|
# NOTE: Only the option tags are returned, you have to wrap this call in
|
567
575
|
# a regular HTML select tag.
|
@@ -573,11 +581,11 @@ module ActionView
|
|
573
581
|
|
574
582
|
if priority_zones
|
575
583
|
if priority_zones.is_a?(Regexp)
|
576
|
-
priority_zones = zones.select { |z| z
|
584
|
+
priority_zones = zones.select { |z| z.match?(priority_zones) }
|
577
585
|
end
|
578
586
|
|
579
587
|
zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
|
580
|
-
zone_options.safe_concat content_tag(
|
588
|
+
zone_options.safe_concat content_tag("option", "-------------", value: "", disabled: true)
|
581
589
|
zone_options.safe_concat "\n"
|
582
590
|
|
583
591
|
zones = zones - priority_zones
|
@@ -586,6 +594,25 @@ module ActionView
|
|
586
594
|
zone_options.safe_concat options_for_select(convert_zones[zones], selected)
|
587
595
|
end
|
588
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 indexes from
|
601
|
+
# `I18n.translate("date.day_names")` as the values. By default, Sunday is always 0.
|
602
|
+
# * <tt>:day_format</tt> - The I18n key of the array to use for the weekday options.
|
603
|
+
# Defaults to :day_names, set to :abbr_day_names for abbreviations.
|
604
|
+
# * <tt>:beginning_of_week</tt> - Defaults to Date.beginning_of_week.
|
605
|
+
#
|
606
|
+
# NOTE: Only the option tags are returned, you have to wrap this call in
|
607
|
+
# a regular HTML select tag.
|
608
|
+
def weekday_options_for_select(selected = nil, index_as_value: false, day_format: :day_names, beginning_of_week: Date.beginning_of_week)
|
609
|
+
day_names = I18n.translate("date.#{day_format}")
|
610
|
+
day_names = day_names.map.with_index.to_a if index_as_value
|
611
|
+
day_names = day_names.rotate(Date::DAYS_INTO_WEEK.fetch(beginning_of_week))
|
612
|
+
|
613
|
+
options_for_select(day_names, selected)
|
614
|
+
end
|
615
|
+
|
589
616
|
# Returns radio button tags for the collection of existing return values
|
590
617
|
# of +method+ for +object+'s class. The value returned from calling
|
591
618
|
# +method+ on the instance +object+ will be selected. If calling +method+
|
@@ -599,11 +626,14 @@ module ActionView
|
|
599
626
|
# retrieve the value/text.
|
600
627
|
#
|
601
628
|
# Example object structure for use with this method:
|
629
|
+
#
|
602
630
|
# class Post < ActiveRecord::Base
|
603
631
|
# belongs_to :author
|
604
632
|
# end
|
633
|
+
#
|
605
634
|
# class Author < ActiveRecord::Base
|
606
635
|
# has_many :posts
|
636
|
+
#
|
607
637
|
# def name_with_initial
|
608
638
|
# "#{first_name.first}. #{last_name}"
|
609
639
|
# end
|
@@ -644,6 +674,24 @@ module ActionView
|
|
644
674
|
# collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b|
|
645
675
|
# b.label(:"data-value" => b.value) { b.radio_button + b.text }
|
646
676
|
# end
|
677
|
+
#
|
678
|
+
# ==== Gotcha
|
679
|
+
#
|
680
|
+
# The HTML specification says when nothing is selected on a collection of radio buttons
|
681
|
+
# web browsers do not send any value to server.
|
682
|
+
# Unfortunately this introduces a gotcha:
|
683
|
+
# if a +User+ model has a +category_id+ field and in the form no category is selected, no +category_id+ parameter is sent. So,
|
684
|
+
# any strong parameters idiom like:
|
685
|
+
#
|
686
|
+
# params.require(:user).permit(...)
|
687
|
+
#
|
688
|
+
# will raise an error since no <tt>{user: ...}</tt> will be present.
|
689
|
+
#
|
690
|
+
# To prevent this the helper generates an auxiliary hidden field before
|
691
|
+
# every collection of radio buttons. The hidden field has the same name as collection radio button and blank value.
|
692
|
+
#
|
693
|
+
# In case if you don't want the helper to generate this hidden field you can specify
|
694
|
+
# <tt>include_hidden: false</tt> option.
|
647
695
|
def collection_radio_buttons(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
648
696
|
Tags::CollectionRadioButtons.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block)
|
649
697
|
end
|
@@ -707,6 +755,27 @@ module ActionView
|
|
707
755
|
# collection_check_boxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b|
|
708
756
|
# b.label(:"data-value" => b.value) { b.check_box + b.text }
|
709
757
|
# end
|
758
|
+
#
|
759
|
+
# ==== Gotcha
|
760
|
+
#
|
761
|
+
# When no selection is made for a collection of checkboxes most
|
762
|
+
# web browsers will not send any value.
|
763
|
+
#
|
764
|
+
# For example, if we have a +User+ model with +category_ids+ field and we
|
765
|
+
# have the following code in our update action:
|
766
|
+
#
|
767
|
+
# @user.update(params[:user])
|
768
|
+
#
|
769
|
+
# If no +category_ids+ are selected then we can safely assume this field
|
770
|
+
# will not be updated.
|
771
|
+
#
|
772
|
+
# This is possible thanks to a hidden field generated by the helper method
|
773
|
+
# for every collection of checkboxes.
|
774
|
+
# This hidden field is given the same field name as the checkboxes with a
|
775
|
+
# blank value.
|
776
|
+
#
|
777
|
+
# In the rare case you don't want this hidden field, you can pass the
|
778
|
+
# <tt>include_hidden: false</tt> option to the helper method.
|
710
779
|
def collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
711
780
|
Tags::CollectionCheckBoxes.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block)
|
712
781
|
end
|
@@ -747,20 +816,20 @@ module ActionView
|
|
747
816
|
|
748
817
|
def extract_values_from_collection(collection, value_method, selected)
|
749
818
|
if selected.is_a?(Proc)
|
750
|
-
collection.
|
751
|
-
element.
|
752
|
-
end
|
819
|
+
collection.filter_map do |element|
|
820
|
+
element.public_send(value_method) if selected.call(element)
|
821
|
+
end
|
753
822
|
else
|
754
823
|
selected
|
755
824
|
end
|
756
825
|
end
|
757
826
|
|
758
827
|
def value_for_collection(item, value)
|
759
|
-
value.respond_to?(:call) ? value.call(item) : item.
|
828
|
+
value.respond_to?(:call) ? value.call(item) : item.public_send(value)
|
760
829
|
end
|
761
830
|
|
762
831
|
def prompt_text(prompt)
|
763
|
-
prompt.kind_of?(String) ? prompt : I18n.translate(
|
832
|
+
prompt.kind_of?(String) ? prompt : I18n.translate("helpers.select.prompt", default: "Please select")
|
764
833
|
end
|
765
834
|
end
|
766
835
|
|
@@ -774,7 +843,7 @@ module ActionView
|
|
774
843
|
#
|
775
844
|
# Please refer to the documentation of the base helper for details.
|
776
845
|
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
777
|
-
@template.select(@object_name, method, choices, objectify_options(options), @
|
846
|
+
@template.select(@object_name, method, choices, objectify_options(options), @default_html_options.merge(html_options), &block)
|
778
847
|
end
|
779
848
|
|
780
849
|
# Wraps ActionView::Helpers::FormOptionsHelper#collection_select for form builders:
|
@@ -786,7 +855,7 @@ module ActionView
|
|
786
855
|
#
|
787
856
|
# Please refer to the documentation of the base helper for details.
|
788
857
|
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
|
789
|
-
@template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @
|
858
|
+
@template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options))
|
790
859
|
end
|
791
860
|
|
792
861
|
# Wraps ActionView::Helpers::FormOptionsHelper#grouped_collection_select for form builders:
|
@@ -798,7 +867,7 @@ module ActionView
|
|
798
867
|
#
|
799
868
|
# Please refer to the documentation of the base helper for details.
|
800
869
|
def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
|
801
|
-
@template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @
|
870
|
+
@template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_html_options.merge(html_options))
|
802
871
|
end
|
803
872
|
|
804
873
|
# Wraps ActionView::Helpers::FormOptionsHelper#time_zone_select for form builders:
|
@@ -810,7 +879,19 @@ module ActionView
|
|
810
879
|
#
|
811
880
|
# Please refer to the documentation of the base helper for details.
|
812
881
|
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
|
813
|
-
@template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @
|
882
|
+
@template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_html_options.merge(html_options))
|
883
|
+
end
|
884
|
+
|
885
|
+
# Wraps ActionView::Helpers::FormOptionsHelper#weekday_select for form builders:
|
886
|
+
#
|
887
|
+
# <%= form_for @user do |f| %>
|
888
|
+
# <%= f.weekday_select :weekday, include_blank: true %>
|
889
|
+
# <%= f.submit %>
|
890
|
+
# <% end %>
|
891
|
+
#
|
892
|
+
# Please refer to the documentation of the base helper for details.
|
893
|
+
def weekday_select(method, options = {}, html_options = {})
|
894
|
+
@template.weekday_select(@object_name, method, objectify_options(options), @default_html_options.merge(html_options))
|
814
895
|
end
|
815
896
|
|
816
897
|
# Wraps ActionView::Helpers::FormOptionsHelper#collection_check_boxes for form builders:
|
@@ -822,7 +903,7 @@ module ActionView
|
|
822
903
|
#
|
823
904
|
# Please refer to the documentation of the base helper for details.
|
824
905
|
def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
825
|
-
@template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @
|
906
|
+
@template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block)
|
826
907
|
end
|
827
908
|
|
828
909
|
# Wraps ActionView::Helpers::FormOptionsHelper#collection_radio_buttons for form builders:
|
@@ -834,7 +915,7 @@ module ActionView
|
|
834
915
|
#
|
835
916
|
# Please refer to the documentation of the base helper for details.
|
836
917
|
def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
837
|
-
@template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @
|
918
|
+
@template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block)
|
838
919
|
end
|
839
920
|
end
|
840
921
|
end
|