actionview 7.1.2 → 8.0.2
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 +4 -4
- data/CHANGELOG.md +51 -382
- data/lib/action_view/base.rb +25 -11
- data/lib/action_view/cache_expiry.rb +9 -3
- data/lib/action_view/dependency_tracker/erb_tracker.rb +36 -27
- data/lib/action_view/dependency_tracker/ruby_tracker.rb +43 -0
- data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
- data/lib/action_view/dependency_tracker.rb +2 -1
- data/lib/action_view/digestor.rb +6 -2
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +18 -6
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -2
- data/lib/action_view/helpers/cache_helper.rb +14 -6
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +282 -273
- data/lib/action_view/helpers/form_options_helper.rb +23 -21
- data/lib/action_view/helpers/form_tag_helper.rb +104 -69
- data/lib/action_view/helpers/number_helper.rb +35 -329
- data/lib/action_view/helpers/output_safety_helper.rb +5 -6
- data/lib/action_view/helpers/rendering_helper.rb +160 -50
- data/lib/action_view/helpers/sanitize_helper.rb +31 -14
- data/lib/action_view/helpers/tag_helper.rb +196 -19
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/text_helper.rb +125 -69
- data/lib/action_view/helpers/url_helper.rb +6 -80
- data/lib/action_view/layouts.rb +11 -13
- data/lib/action_view/log_subscriber.rb +8 -4
- data/lib/action_view/railtie.rb +0 -1
- data/lib/action_view/record_identifier.rb +1 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +139 -0
- data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +162 -10
- data/lib/action_view/render_parser.rb +21 -169
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/renderer.rb +32 -38
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -1
- data/lib/action_view/renderer/template_renderer.rb +3 -3
- data/lib/action_view/rendering.rb +6 -7
- data/lib/action_view/template/error.rb +11 -0
- data/lib/action_view/template/handlers/erb.rb +45 -37
- data/lib/action_view/template/renderable.rb +7 -1
- data/lib/action_view/template/resolver.rb +0 -3
- data/lib/action_view/template.rb +46 -12
- data/lib/action_view/test_case.rb +14 -16
- data/lib/action_view/unbound_template.rb +4 -4
- data/lib/action_view.rb +1 -1
- metadata +17 -19
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +0 -59
- data/lib/assets/compiled/rails-ujs.js +0 -777
|
@@ -7,6 +7,7 @@ require "action_view/helpers/form_tag_helper"
|
|
|
7
7
|
require "action_view/helpers/active_model_helper"
|
|
8
8
|
require "action_view/model_naming"
|
|
9
9
|
require "action_view/record_identifier"
|
|
10
|
+
require "active_support/code_generator"
|
|
10
11
|
require "active_support/core_ext/module/attribute_accessors"
|
|
11
12
|
require "active_support/core_ext/hash/slice"
|
|
12
13
|
require "active_support/core_ext/string/output_safety"
|
|
@@ -29,20 +30,21 @@ module ActionView
|
|
|
29
30
|
# when the form is initially displayed, input fields corresponding to attributes
|
|
30
31
|
# of the resource should show the current values of those attributes.
|
|
31
32
|
#
|
|
32
|
-
# In \Rails, this is usually achieved by creating the form using
|
|
33
|
-
# a number of related helper methods.
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
33
|
+
# In \Rails, this is usually achieved by creating the form using either
|
|
34
|
+
# #form_with or #form_for and a number of related helper methods. These
|
|
35
|
+
# methods generate an appropriate <tt>form</tt> tag and yield a form
|
|
36
|
+
# builder object that knows the model the form is about. Input fields are
|
|
37
|
+
# created by calling methods defined on the form builder, which means they
|
|
38
|
+
# are able to generate the appropriate names and default values
|
|
37
39
|
# corresponding to the model attributes, as well as convenient IDs, etc.
|
|
38
|
-
# Conventions in the generated field names allow controllers to receive form
|
|
39
|
-
# nicely structured in +params+ with no effort on your side.
|
|
40
|
+
# Conventions in the generated field names allow controllers to receive form
|
|
41
|
+
# data nicely structured in +params+ with no effort on your side.
|
|
40
42
|
#
|
|
41
43
|
# For example, to create a new person you typically set up a new instance of
|
|
42
44
|
# +Person+ in the <tt>PeopleController#new</tt> action, <tt>@person</tt>, and
|
|
43
|
-
# in the view template pass that object to
|
|
45
|
+
# in the view template pass that object to #form_with or #form_for:
|
|
44
46
|
#
|
|
45
|
-
# <%=
|
|
47
|
+
# <%= form_with model: @person do |f| %>
|
|
46
48
|
# <%= f.label :first_name %>:
|
|
47
49
|
# <%= f.text_field :first_name %><br />
|
|
48
50
|
#
|
|
@@ -131,8 +133,8 @@ module ActionView
|
|
|
131
133
|
# <%= form_for :person do |f| %>
|
|
132
134
|
# First name: <%= f.text_field :first_name %><br />
|
|
133
135
|
# Last name : <%= f.text_field :last_name %><br />
|
|
134
|
-
# Biography : <%= f.
|
|
135
|
-
# Admin? : <%= f.
|
|
136
|
+
# Biography : <%= f.textarea :biography %><br />
|
|
137
|
+
# Admin? : <%= f.checkbox :admin %><br />
|
|
136
138
|
# <%= f.submit %>
|
|
137
139
|
# <% end %>
|
|
138
140
|
#
|
|
@@ -198,8 +200,8 @@ module ActionView
|
|
|
198
200
|
# <%= form_for :person do |f| %>
|
|
199
201
|
# First name: <%= f.text_field :first_name %>
|
|
200
202
|
# Last name : <%= f.text_field :last_name %>
|
|
201
|
-
# Biography : <%=
|
|
202
|
-
# Admin? : <%=
|
|
203
|
+
# Biography : <%= textarea :person, :biography %>
|
|
204
|
+
# Admin? : <%= checkbox_tag "person[admin]", "1", @person.company.admin? %>
|
|
203
205
|
# <%= f.submit %>
|
|
204
206
|
# <% end %>
|
|
205
207
|
#
|
|
@@ -207,23 +209,23 @@ module ActionView
|
|
|
207
209
|
# are designed to work with an object as base, like
|
|
208
210
|
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
|
|
209
211
|
#
|
|
210
|
-
# ===
|
|
212
|
+
# === +form_for+ with a model object
|
|
211
213
|
#
|
|
212
214
|
# In the examples above, the object to be created or edited was
|
|
213
215
|
# represented by a symbol passed to +form_for+, and we noted that
|
|
214
216
|
# a string can also be used equivalently. It is also possible, however,
|
|
215
|
-
# to pass a model object itself to +form_for+. For example, if <tt>@
|
|
217
|
+
# to pass a model object itself to +form_for+. For example, if <tt>@article</tt>
|
|
216
218
|
# is an existing record you wish to edit, you can create the form using
|
|
217
219
|
#
|
|
218
|
-
# <%= form_for @
|
|
220
|
+
# <%= form_for @article do |f| %>
|
|
219
221
|
# ...
|
|
220
222
|
# <% end %>
|
|
221
223
|
#
|
|
222
224
|
# This behaves in almost the same way as outlined previously, with a
|
|
223
225
|
# couple of small exceptions. First, the prefix used to name the input
|
|
224
226
|
# elements within the form (hence the key that denotes them in the +params+
|
|
225
|
-
# hash) is actually derived from the object's _class_, e.g. <tt>params[:
|
|
226
|
-
# if the object's class is +
|
|
227
|
+
# hash) is actually derived from the object's _class_, e.g. <tt>params[:article]</tt>
|
|
228
|
+
# if the object's class is +Article+. However, this can be overwritten using
|
|
227
229
|
# the <tt>:as</tt> option, e.g. -
|
|
228
230
|
#
|
|
229
231
|
# <%= form_for(@person, as: :client) do |f| %>
|
|
@@ -235,15 +237,15 @@ module ActionView
|
|
|
235
237
|
# Secondly, the field values shown when the form is initially displayed
|
|
236
238
|
# are taken from the attributes of the object passed to +form_for+,
|
|
237
239
|
# regardless of whether the object is an instance
|
|
238
|
-
# variable. So, for example, if we had a _local_ variable +
|
|
240
|
+
# variable. So, for example, if we had a _local_ variable +article+
|
|
239
241
|
# representing an existing record,
|
|
240
242
|
#
|
|
241
|
-
# <%= form_for
|
|
243
|
+
# <%= form_for article do |f| %>
|
|
242
244
|
# ...
|
|
243
245
|
# <% end %>
|
|
244
246
|
#
|
|
245
247
|
# would produce a form with fields whose initial state reflect the current
|
|
246
|
-
# values of the attributes of +
|
|
248
|
+
# values of the attributes of +article+.
|
|
247
249
|
#
|
|
248
250
|
# === Resource-oriented style
|
|
249
251
|
#
|
|
@@ -255,49 +257,49 @@ module ActionView
|
|
|
255
257
|
# in <tt>config/routes.rb</tt>. In this case \Rails will simply infer the
|
|
256
258
|
# appropriate URL from the record itself. For example,
|
|
257
259
|
#
|
|
258
|
-
# <%= form_for @
|
|
260
|
+
# <%= form_for @article do |f| %>
|
|
259
261
|
# ...
|
|
260
262
|
# <% end %>
|
|
261
263
|
#
|
|
262
264
|
# is then equivalent to something like:
|
|
263
265
|
#
|
|
264
|
-
# <%= form_for @
|
|
266
|
+
# <%= form_for @article, as: :article, url: article_path(@article), method: :patch, html: { class: "edit_article", id: "edit_article_45" } do |f| %>
|
|
265
267
|
# ...
|
|
266
268
|
# <% end %>
|
|
267
269
|
#
|
|
268
270
|
# And for a new record
|
|
269
271
|
#
|
|
270
|
-
# <%= form_for(
|
|
272
|
+
# <%= form_for(Article.new) do |f| %>
|
|
271
273
|
# ...
|
|
272
274
|
# <% end %>
|
|
273
275
|
#
|
|
274
276
|
# is equivalent to something like:
|
|
275
277
|
#
|
|
276
|
-
# <%= form_for @
|
|
278
|
+
# <%= form_for @article, as: :article, url: articles_path, html: { class: "new_article", id: "new_article" } do |f| %>
|
|
277
279
|
# ...
|
|
278
280
|
# <% end %>
|
|
279
281
|
#
|
|
280
282
|
# However you can still overwrite individual conventions, such as:
|
|
281
283
|
#
|
|
282
|
-
# <%= form_for(@
|
|
284
|
+
# <%= form_for(@article, url: super_articles_path) do |f| %>
|
|
283
285
|
# ...
|
|
284
286
|
# <% end %>
|
|
285
287
|
#
|
|
286
288
|
# You can omit the <tt>action</tt> attribute by passing <tt>url: false</tt>:
|
|
287
289
|
#
|
|
288
|
-
# <%= form_for(@
|
|
290
|
+
# <%= form_for(@article, url: false) do |f| %>
|
|
289
291
|
# ...
|
|
290
292
|
# <% end %>
|
|
291
293
|
#
|
|
292
294
|
# You can also set the answer format, like this:
|
|
293
295
|
#
|
|
294
|
-
# <%= form_for(@
|
|
296
|
+
# <%= form_for(@article, format: :json) do |f| %>
|
|
295
297
|
# ...
|
|
296
298
|
# <% end %>
|
|
297
299
|
#
|
|
298
|
-
# For namespaced routes, like +
|
|
300
|
+
# For namespaced routes, like +admin_article_url+:
|
|
299
301
|
#
|
|
300
|
-
# <%= form_for([:admin, @
|
|
302
|
+
# <%= form_for([:admin, @article]) do |f| %>
|
|
301
303
|
# ...
|
|
302
304
|
# <% end %>
|
|
303
305
|
#
|
|
@@ -333,7 +335,7 @@ module ActionView
|
|
|
333
335
|
#
|
|
334
336
|
# Example:
|
|
335
337
|
#
|
|
336
|
-
# <%= form_for(@
|
|
338
|
+
# <%= form_for(@article, remote: true) do |f| %>
|
|
337
339
|
# ...
|
|
338
340
|
# <% end %>
|
|
339
341
|
#
|
|
@@ -349,7 +351,7 @@ module ActionView
|
|
|
349
351
|
# You can set data attributes directly by passing in a data hash, but all other HTML options must be wrapped in
|
|
350
352
|
# the HTML key. Example:
|
|
351
353
|
#
|
|
352
|
-
# <%= form_for(@
|
|
354
|
+
# <%= form_for(@article, data: { behavior: "autosave" }, html: { name: "go" }) do |f| %>
|
|
353
355
|
# ...
|
|
354
356
|
# <% end %>
|
|
355
357
|
#
|
|
@@ -362,17 +364,17 @@ module ActionView
|
|
|
362
364
|
#
|
|
363
365
|
# === Removing hidden model id's
|
|
364
366
|
#
|
|
365
|
-
# The form_for method automatically includes the model id as a hidden field in the form.
|
|
367
|
+
# The +form_for+ method automatically includes the model id as a hidden field in the form.
|
|
366
368
|
# This is used to maintain the correlation between the form data and its associated model.
|
|
367
369
|
# Some ORM systems do not use IDs on nested models so in this case you want to be able
|
|
368
370
|
# to disable the hidden id.
|
|
369
371
|
#
|
|
370
|
-
# In the following example the
|
|
372
|
+
# In the following example the Article model has many Comments stored within it in a NoSQL database,
|
|
371
373
|
# thus there is no primary key for comments.
|
|
372
374
|
#
|
|
373
375
|
# Example:
|
|
374
376
|
#
|
|
375
|
-
# <%= form_for(@
|
|
377
|
+
# <%= form_for(@article) do |f| %>
|
|
376
378
|
# <%= f.fields_for(:comments, include_id: false) do |cf| %>
|
|
377
379
|
# ...
|
|
378
380
|
# <% end %>
|
|
@@ -388,8 +390,8 @@ module ActionView
|
|
|
388
390
|
# <%= form_for @person, url: { action: "create" }, builder: LabellingFormBuilder do |f| %>
|
|
389
391
|
# <%= f.text_field :first_name %>
|
|
390
392
|
# <%= f.text_field :last_name %>
|
|
391
|
-
# <%= f.
|
|
392
|
-
# <%= f.
|
|
393
|
+
# <%= f.textarea :biography %>
|
|
394
|
+
# <%= f.checkbox :admin %>
|
|
393
395
|
# <%= f.submit %>
|
|
394
396
|
# <% end %>
|
|
395
397
|
#
|
|
@@ -436,7 +438,7 @@ module ActionView
|
|
|
436
438
|
|
|
437
439
|
case record
|
|
438
440
|
when String, Symbol
|
|
439
|
-
model =
|
|
441
|
+
model = false
|
|
440
442
|
object_name = record
|
|
441
443
|
else
|
|
442
444
|
model = record
|
|
@@ -484,12 +486,12 @@ module ActionView
|
|
|
484
486
|
# Creates a form tag based on mixing URLs, scopes, or models.
|
|
485
487
|
#
|
|
486
488
|
# # Using just a URL:
|
|
487
|
-
# <%= form_with url:
|
|
489
|
+
# <%= form_with url: articles_path do |form| %>
|
|
488
490
|
# <%= form.text_field :title %>
|
|
489
491
|
# <% end %>
|
|
490
492
|
# # =>
|
|
491
|
-
# <form action="/
|
|
492
|
-
# <input type="text" name="title"
|
|
493
|
+
# <form action="/articles" method="post">
|
|
494
|
+
# <input type="text" name="title" />
|
|
493
495
|
# </form>
|
|
494
496
|
#
|
|
495
497
|
# # With an intentionally empty URL:
|
|
@@ -498,37 +500,36 @@ module ActionView
|
|
|
498
500
|
# <% end %>
|
|
499
501
|
# # =>
|
|
500
502
|
# <form method="post">
|
|
501
|
-
# <input type="text" name="title"
|
|
503
|
+
# <input type="text" name="title" />
|
|
502
504
|
# </form>
|
|
503
505
|
#
|
|
504
506
|
# # Adding a scope prefixes the input field names:
|
|
505
|
-
# <%= form_with scope: :
|
|
507
|
+
# <%= form_with scope: :article, url: articles_path do |form| %>
|
|
506
508
|
# <%= form.text_field :title %>
|
|
507
509
|
# <% end %>
|
|
508
510
|
# # =>
|
|
509
|
-
# <form action="/
|
|
510
|
-
# <input type="text" name="
|
|
511
|
+
# <form action="/articles" method="post">
|
|
512
|
+
# <input type="text" name="article[title]" />
|
|
511
513
|
# </form>
|
|
512
514
|
#
|
|
513
515
|
# # Using a model infers both the URL and scope:
|
|
514
|
-
# <%= form_with model:
|
|
516
|
+
# <%= form_with model: Article.new do |form| %>
|
|
515
517
|
# <%= form.text_field :title %>
|
|
516
518
|
# <% end %>
|
|
517
519
|
# # =>
|
|
518
|
-
# <form action="/
|
|
519
|
-
# <input type="text" name="
|
|
520
|
+
# <form action="/articles" method="post">
|
|
521
|
+
# <input type="text" name="article[title]" />
|
|
520
522
|
# </form>
|
|
521
523
|
#
|
|
522
524
|
# # An existing model makes an update form and fills out field values:
|
|
523
|
-
# <%= form_with model:
|
|
525
|
+
# <%= form_with model: Article.first do |form| %>
|
|
524
526
|
# <%= form.text_field :title %>
|
|
525
527
|
# <% end %>
|
|
526
528
|
# # =>
|
|
527
|
-
# <form action="/
|
|
528
|
-
# <input type="hidden" name="_method" value="patch"
|
|
529
|
-
# <input type="text" name="
|
|
529
|
+
# <form action="/articles/1" method="post">
|
|
530
|
+
# <input type="hidden" name="_method" value="patch" />
|
|
531
|
+
# <input type="text" name="article[title]" value="<the title of the article>" />
|
|
530
532
|
# </form>
|
|
531
|
-
#
|
|
532
533
|
# # Though the fields don't have to correspond to model attributes:
|
|
533
534
|
# <%= form_with model: Cat.new do |form| %>
|
|
534
535
|
# <%= form.text_field :cats_dont_have_gills %>
|
|
@@ -536,13 +537,13 @@ module ActionView
|
|
|
536
537
|
# <% end %>
|
|
537
538
|
# # =>
|
|
538
539
|
# <form action="/cats" method="post">
|
|
539
|
-
# <input type="text" name="cat[cats_dont_have_gills]"
|
|
540
|
-
# <input type="text" name="cat[but_in_forms_they_can]"
|
|
540
|
+
# <input type="text" name="cat[cats_dont_have_gills]" />
|
|
541
|
+
# <input type="text" name="cat[but_in_forms_they_can]" />
|
|
541
542
|
# </form>
|
|
542
543
|
#
|
|
543
544
|
# The parameters in the forms are accessible in controllers according to
|
|
544
|
-
# their name nesting. So inputs named +title+ and <tt>
|
|
545
|
-
# accessible as <tt>params[:title]</tt> and <tt>params[:
|
|
545
|
+
# their name nesting. So inputs named +title+ and <tt>article[title]</tt> are
|
|
546
|
+
# accessible as <tt>params[:title]</tt> and <tt>params[:article][:title]</tt>
|
|
546
547
|
# respectively.
|
|
547
548
|
#
|
|
548
549
|
# For ease of comparison the examples above left out the submit button,
|
|
@@ -558,25 +559,25 @@ module ActionView
|
|
|
558
559
|
#
|
|
559
560
|
# So when passing such a model record, \Rails infers the URL and method.
|
|
560
561
|
#
|
|
561
|
-
# <%= form_with model: @
|
|
562
|
+
# <%= form_with model: @article do |form| %>
|
|
562
563
|
# ...
|
|
563
564
|
# <% end %>
|
|
564
565
|
#
|
|
565
566
|
# is then equivalent to something like:
|
|
566
567
|
#
|
|
567
|
-
# <%= form_with scope: :
|
|
568
|
+
# <%= form_with scope: :article, url: article_path(@article), method: :patch do |form| %>
|
|
568
569
|
# ...
|
|
569
570
|
# <% end %>
|
|
570
571
|
#
|
|
571
572
|
# And for a new record
|
|
572
573
|
#
|
|
573
|
-
# <%= form_with model:
|
|
574
|
+
# <%= form_with model: Article.new do |form| %>
|
|
574
575
|
# ...
|
|
575
576
|
# <% end %>
|
|
576
577
|
#
|
|
577
578
|
# is equivalent to something like:
|
|
578
579
|
#
|
|
579
|
-
# <%= form_with scope: :
|
|
580
|
+
# <%= form_with scope: :article, url: articles_path do |form| %>
|
|
580
581
|
# ...
|
|
581
582
|
# <% end %>
|
|
582
583
|
#
|
|
@@ -605,7 +606,7 @@ module ActionView
|
|
|
605
606
|
# If the model is a new record a create form is generated, if an
|
|
606
607
|
# existing record, however, an update form is generated.
|
|
607
608
|
# Pass <tt>:scope</tt> or <tt>:url</tt> to override the defaults.
|
|
608
|
-
# E.g. turn <tt>params[:
|
|
609
|
+
# E.g. turn <tt>params[:article]</tt> into <tt>params[:blog]</tt>.
|
|
609
610
|
# * <tt>:authenticity_token</tt> - Authenticity token to use in the form.
|
|
610
611
|
# Override with a custom authenticity token or pass <tt>false</tt> to
|
|
611
612
|
# skip the authenticity token field altogether.
|
|
@@ -638,14 +639,14 @@ module ActionView
|
|
|
638
639
|
#
|
|
639
640
|
# When not passing a block, +form_with+ just generates an opening form tag.
|
|
640
641
|
#
|
|
641
|
-
# <%= form_with(model: @
|
|
642
|
-
# <%= form_with(model: @
|
|
643
|
-
# <%= form_with(model: @
|
|
644
|
-
# <%= form_with(model: @
|
|
642
|
+
# <%= form_with(model: @article, url: super_articles_path) %>
|
|
643
|
+
# <%= form_with(model: @article, scope: :blog) %>
|
|
644
|
+
# <%= form_with(model: @article, format: :json) %>
|
|
645
|
+
# <%= form_with(model: @article, authenticity_token: false) %> # Disables the token.
|
|
645
646
|
#
|
|
646
|
-
# For namespaced routes, like +
|
|
647
|
+
# For namespaced routes, like +admin_article_url+:
|
|
647
648
|
#
|
|
648
|
-
# <%= form_with(model: [ :admin, @
|
|
649
|
+
# <%= form_with(model: [ :admin, @article ]) do |form| %>
|
|
649
650
|
# ...
|
|
650
651
|
# <% end %>
|
|
651
652
|
#
|
|
@@ -668,8 +669,8 @@ module ActionView
|
|
|
668
669
|
# <%= form.text_field :first_name %>
|
|
669
670
|
# <%= form.text_field :last_name %>
|
|
670
671
|
#
|
|
671
|
-
# <%=
|
|
672
|
-
# <%=
|
|
672
|
+
# <%= textarea :person, :biography %>
|
|
673
|
+
# <%= checkbox_tag "person[admin]", "1", @person.company.admin? %>
|
|
673
674
|
#
|
|
674
675
|
# <%= form.submit %>
|
|
675
676
|
# <% end %>
|
|
@@ -693,13 +694,13 @@ module ActionView
|
|
|
693
694
|
# You can set data attributes directly in a data hash, but HTML options
|
|
694
695
|
# besides id and class must be wrapped in an HTML key:
|
|
695
696
|
#
|
|
696
|
-
# <%= form_with(model: @
|
|
697
|
+
# <%= form_with(model: @article, data: { behavior: "autosave" }, html: { name: "go" }) do |form| %>
|
|
697
698
|
# ...
|
|
698
699
|
# <% end %>
|
|
699
700
|
#
|
|
700
701
|
# generates
|
|
701
702
|
#
|
|
702
|
-
# <form action="/
|
|
703
|
+
# <form action="/articles/123" method="post" data-behavior="autosave" name="go">
|
|
703
704
|
# <input name="_method" type="hidden" value="patch" />
|
|
704
705
|
# ...
|
|
705
706
|
# </form>
|
|
@@ -711,10 +712,10 @@ module ActionView
|
|
|
711
712
|
# Some ORM systems do not use IDs on nested models so in this case you want to be able
|
|
712
713
|
# to disable the hidden id.
|
|
713
714
|
#
|
|
714
|
-
# In the following example the
|
|
715
|
+
# In the following example the Article model has many Comments stored within it in a NoSQL database,
|
|
715
716
|
# thus there is no primary key for comments.
|
|
716
717
|
#
|
|
717
|
-
# <%= form_with(model: @
|
|
718
|
+
# <%= form_with(model: @article) do |form| %>
|
|
718
719
|
# <%= form.fields(:comments, skip_id: true) do |fields| %>
|
|
719
720
|
# ...
|
|
720
721
|
# <% end %>
|
|
@@ -730,8 +731,8 @@ module ActionView
|
|
|
730
731
|
# <%= form_with model: @person, url: { action: "create" }, builder: LabellingFormBuilder do |form| %>
|
|
731
732
|
# <%= form.text_field :first_name %>
|
|
732
733
|
# <%= form.text_field :last_name %>
|
|
733
|
-
# <%= form.
|
|
734
|
-
# <%= form.
|
|
734
|
+
# <%= form.textarea :biography %>
|
|
735
|
+
# <%= form.checkbox :admin %>
|
|
735
736
|
# <%= form.submit %>
|
|
736
737
|
# <% end %>
|
|
737
738
|
#
|
|
@@ -752,7 +753,9 @@ module ActionView
|
|
|
752
753
|
# def labelled_form_with(**options, &block)
|
|
753
754
|
# form_with(**options.merge(builder: LabellingFormBuilder), &block)
|
|
754
755
|
# end
|
|
755
|
-
def form_with(model:
|
|
756
|
+
def form_with(model: false, scope: nil, url: nil, format: nil, **options, &block)
|
|
757
|
+
raise ArgumentError, "Passed nil to the :model argument, expect an object or false" if model.nil?
|
|
758
|
+
|
|
756
759
|
options = { allow_method_names_outside_object: true, skip_default_ids: !form_with_generates_ids }.merge!(options)
|
|
757
760
|
|
|
758
761
|
if model
|
|
@@ -781,28 +784,28 @@ module ActionView
|
|
|
781
784
|
end
|
|
782
785
|
end
|
|
783
786
|
|
|
784
|
-
# Creates a scope around a specific model object like
|
|
785
|
-
# doesn't create the form tags themselves. This makes fields_for
|
|
786
|
-
# for specifying additional model objects in the same form.
|
|
787
|
+
# Creates a scope around a specific model object like #form_with, but
|
|
788
|
+
# doesn't create the form tags themselves. This makes +fields_for+
|
|
789
|
+
# suitable for specifying additional model objects in the same form.
|
|
787
790
|
#
|
|
788
|
-
# Although the usage and purpose of +fields_for+ is similar to
|
|
789
|
-
# its method signature is slightly different. Like
|
|
791
|
+
# Although the usage and purpose of +fields_for+ is similar to #form_with's,
|
|
792
|
+
# its method signature is slightly different. Like #form_with, it yields
|
|
790
793
|
# a FormBuilder object associated with a particular model object to a block,
|
|
791
794
|
# and within the block allows methods to be called on the builder to
|
|
792
795
|
# generate fields associated with the model object. Fields may reflect
|
|
793
796
|
# a model object in two ways - how they are named (hence how submitted
|
|
794
797
|
# values appear within the +params+ hash in the controller) and what
|
|
795
|
-
# default values are shown when the form
|
|
796
|
-
#
|
|
798
|
+
# default values are shown when the form fields are first displayed.
|
|
799
|
+
# In order for both of these features to be specified independently,
|
|
797
800
|
# both an object name (represented by either a symbol or string) and the
|
|
798
801
|
# object itself can be passed to the method separately -
|
|
799
802
|
#
|
|
800
|
-
# <%=
|
|
803
|
+
# <%= form_with model: @person do |person_form| %>
|
|
801
804
|
# First name: <%= person_form.text_field :first_name %>
|
|
802
805
|
# Last name : <%= person_form.text_field :last_name %>
|
|
803
806
|
#
|
|
804
807
|
# <%= fields_for :permission, @person.permission do |permission_fields| %>
|
|
805
|
-
# Admin? : <%= permission_fields.
|
|
808
|
+
# Admin? : <%= permission_fields.checkbox :admin %>
|
|
806
809
|
# <% end %>
|
|
807
810
|
#
|
|
808
811
|
# <%= person_form.submit %>
|
|
@@ -819,7 +822,7 @@ module ActionView
|
|
|
819
822
|
# object to +fields_for+ -
|
|
820
823
|
#
|
|
821
824
|
# <%= fields_for :permission do |permission_fields| %>
|
|
822
|
-
# Admin?: <%= permission_fields.
|
|
825
|
+
# Admin?: <%= permission_fields.checkbox :admin %>
|
|
823
826
|
# <% end %>
|
|
824
827
|
#
|
|
825
828
|
# ...in which case, if <tt>:permission</tt> also happens to be the name of an
|
|
@@ -831,7 +834,7 @@ module ActionView
|
|
|
831
834
|
# name has been omitted) -
|
|
832
835
|
#
|
|
833
836
|
# <%= fields_for @person.permission do |permission_fields| %>
|
|
834
|
-
# Admin?: <%= permission_fields.
|
|
837
|
+
# Admin?: <%= permission_fields.checkbox :admin %>
|
|
835
838
|
# <% end %>
|
|
836
839
|
#
|
|
837
840
|
# and +fields_for+ will derive the required name of the field from the
|
|
@@ -845,7 +848,7 @@ module ActionView
|
|
|
845
848
|
# === Nested Attributes Examples
|
|
846
849
|
#
|
|
847
850
|
# When the object belonging to the current scope has a nested attribute
|
|
848
|
-
# writer for a certain attribute, fields_for will yield a new scope
|
|
851
|
+
# writer for a certain attribute, +fields_for+ will yield a new scope
|
|
849
852
|
# for that attribute. This allows you to create forms that set or change
|
|
850
853
|
# the attributes of a parent object and its associations in one go.
|
|
851
854
|
#
|
|
@@ -878,7 +881,7 @@ module ActionView
|
|
|
878
881
|
#
|
|
879
882
|
# This model can now be used with a nested fields_for, like so:
|
|
880
883
|
#
|
|
881
|
-
# <%=
|
|
884
|
+
# <%= form_with model: @person do |person_form| %>
|
|
882
885
|
# ...
|
|
883
886
|
# <%= person_form.fields_for :address do |address_fields| %>
|
|
884
887
|
# Street : <%= address_fields.text_field :street %>
|
|
@@ -908,11 +911,11 @@ module ActionView
|
|
|
908
911
|
# with a value that evaluates to +true+, you will destroy the associated
|
|
909
912
|
# model (e.g. 1, '1', true, or 'true'):
|
|
910
913
|
#
|
|
911
|
-
# <%=
|
|
914
|
+
# <%= form_with model: @person do |person_form| %>
|
|
912
915
|
# ...
|
|
913
916
|
# <%= person_form.fields_for :address do |address_fields| %>
|
|
914
917
|
# ...
|
|
915
|
-
# Delete: <%= address_fields.
|
|
918
|
+
# Delete: <%= address_fields.checkbox :_destroy %>
|
|
916
919
|
# <% end %>
|
|
917
920
|
# ...
|
|
918
921
|
# <% end %>
|
|
@@ -934,7 +937,7 @@ module ActionView
|
|
|
934
937
|
# end
|
|
935
938
|
#
|
|
936
939
|
# Note that the <tt>projects_attributes=</tt> writer method is in fact
|
|
937
|
-
# required for fields_for to correctly identify <tt>:projects</tt> as a
|
|
940
|
+
# required for +fields_for+ to correctly identify <tt>:projects</tt> as a
|
|
938
941
|
# collection, and the correct indices to be set in the form markup.
|
|
939
942
|
#
|
|
940
943
|
# When projects is already an association on Person you can use
|
|
@@ -946,10 +949,10 @@ module ActionView
|
|
|
946
949
|
# end
|
|
947
950
|
#
|
|
948
951
|
# This model can now be used with a nested fields_for. The block given to
|
|
949
|
-
# the nested fields_for call will be repeated for each instance in the
|
|
952
|
+
# the nested +fields_for+ call will be repeated for each instance in the
|
|
950
953
|
# collection:
|
|
951
954
|
#
|
|
952
|
-
# <%=
|
|
955
|
+
# <%= form_with model: @person do |person_form| %>
|
|
953
956
|
# ...
|
|
954
957
|
# <%= person_form.fields_for :projects do |project_fields| %>
|
|
955
958
|
# <% if project_fields.object.active? %>
|
|
@@ -961,7 +964,7 @@ module ActionView
|
|
|
961
964
|
#
|
|
962
965
|
# It's also possible to specify the instance to be used:
|
|
963
966
|
#
|
|
964
|
-
# <%=
|
|
967
|
+
# <%= form_with model: @person do |person_form| %>
|
|
965
968
|
# ...
|
|
966
969
|
# <% @person.projects.each do |project| %>
|
|
967
970
|
# <% if project.active? %>
|
|
@@ -975,7 +978,7 @@ module ActionView
|
|
|
975
978
|
#
|
|
976
979
|
# Or a collection to be used:
|
|
977
980
|
#
|
|
978
|
-
# <%=
|
|
981
|
+
# <%= form_with model: @person do |person_form| %>
|
|
979
982
|
# ...
|
|
980
983
|
# <%= person_form.fields_for :projects, @active_projects do |project_fields| %>
|
|
981
984
|
# Name: <%= project_fields.text_field :name %>
|
|
@@ -997,19 +1000,19 @@ module ActionView
|
|
|
997
1000
|
# parameter with a value that evaluates to +true+
|
|
998
1001
|
# (e.g. 1, '1', true, or 'true'):
|
|
999
1002
|
#
|
|
1000
|
-
# <%=
|
|
1003
|
+
# <%= form_with model: @person do |person_form| %>
|
|
1001
1004
|
# ...
|
|
1002
1005
|
# <%= person_form.fields_for :projects do |project_fields| %>
|
|
1003
|
-
# Delete: <%= project_fields.
|
|
1006
|
+
# Delete: <%= project_fields.checkbox :_destroy %>
|
|
1004
1007
|
# <% end %>
|
|
1005
1008
|
# ...
|
|
1006
1009
|
# <% end %>
|
|
1007
1010
|
#
|
|
1008
1011
|
# When a collection is used you might want to know the index of each
|
|
1009
|
-
# object
|
|
1010
|
-
#
|
|
1012
|
+
# object in the array. For this purpose, the <tt>index</tt> method is
|
|
1013
|
+
# available in the FormBuilder object.
|
|
1011
1014
|
#
|
|
1012
|
-
# <%=
|
|
1015
|
+
# <%= form_with model: @person do |person_form| %>
|
|
1013
1016
|
# ...
|
|
1014
1017
|
# <%= person_form.fields_for :projects do |project_fields| %>
|
|
1015
1018
|
# Project #<%= project_fields.index %>
|
|
@@ -1018,10 +1021,10 @@ module ActionView
|
|
|
1018
1021
|
# ...
|
|
1019
1022
|
# <% end %>
|
|
1020
1023
|
#
|
|
1021
|
-
# Note that fields_for will automatically generate a hidden field
|
|
1024
|
+
# Note that +fields_for+ will automatically generate a hidden field
|
|
1022
1025
|
# to store the ID of the record if it responds to <tt>persisted?</tt>.
|
|
1023
1026
|
# There are circumstances where this hidden field is not needed and you
|
|
1024
|
-
# can pass <tt>include_id: false</tt> to prevent fields_for from
|
|
1027
|
+
# can pass <tt>include_id: false</tt> to prevent +fields_for+ from
|
|
1025
1028
|
# rendering it automatically.
|
|
1026
1029
|
def fields_for(record_name, record_object = nil, options = {}, &block)
|
|
1027
1030
|
options = { model: record_object, allow_method_names_outside_object: false, skip_default_ids: false }.merge!(options)
|
|
@@ -1030,7 +1033,7 @@ module ActionView
|
|
|
1030
1033
|
end
|
|
1031
1034
|
|
|
1032
1035
|
# Scopes input fields with either an explicit scope or model.
|
|
1033
|
-
# Like
|
|
1036
|
+
# Like #form_with does with <tt>:scope</tt> or <tt>:model</tt>,
|
|
1034
1037
|
# except it doesn't output the form tags.
|
|
1035
1038
|
#
|
|
1036
1039
|
# # Using a scope prefixes the input field names:
|
|
@@ -1045,8 +1048,8 @@ module ActionView
|
|
|
1045
1048
|
# <% end %>
|
|
1046
1049
|
# # => <input type="text" name="comment[body]" value="full bodied">
|
|
1047
1050
|
#
|
|
1048
|
-
# # Using
|
|
1049
|
-
# <%= form_with model: @
|
|
1051
|
+
# # Using `fields` with `form_with`:
|
|
1052
|
+
# <%= form_with model: @article do |form| %>
|
|
1050
1053
|
# <%= form.text_field :title %>
|
|
1051
1054
|
#
|
|
1052
1055
|
# <%= form.fields :comment do |fields| %>
|
|
@@ -1054,21 +1057,21 @@ module ActionView
|
|
|
1054
1057
|
# <% end %>
|
|
1055
1058
|
# <% end %>
|
|
1056
1059
|
#
|
|
1057
|
-
# Much like
|
|
1060
|
+
# Much like #form_with a FormBuilder instance associated with the scope
|
|
1058
1061
|
# or model is yielded, so any generated field names are prefixed with
|
|
1059
1062
|
# either the passed scope or the scope inferred from the <tt>:model</tt>.
|
|
1060
1063
|
#
|
|
1061
1064
|
# === Mixing with other form helpers
|
|
1062
1065
|
#
|
|
1063
|
-
# While
|
|
1066
|
+
# While #form_with uses a FormBuilder object it's possible to mix and
|
|
1064
1067
|
# match the stand-alone FormHelper methods and methods
|
|
1065
1068
|
# from FormTagHelper:
|
|
1066
1069
|
#
|
|
1067
1070
|
# <%= fields model: @comment do |fields| %>
|
|
1068
1071
|
# <%= fields.text_field :body %>
|
|
1069
1072
|
#
|
|
1070
|
-
# <%=
|
|
1071
|
-
# <%=
|
|
1073
|
+
# <%= textarea :commenter, :biography %>
|
|
1074
|
+
# <%= checkbox_tag "comment[all_caps]", "1", @comment.commenter.hulk_mode? %>
|
|
1072
1075
|
# <% end %>
|
|
1073
1076
|
#
|
|
1074
1077
|
# Same goes for the methods in FormOptionsHelper and DateHelper designed
|
|
@@ -1094,56 +1097,58 @@ module ActionView
|
|
|
1094
1097
|
# target labels for radio_button tags (where the value is used in the ID of the input tag).
|
|
1095
1098
|
#
|
|
1096
1099
|
# ==== Examples
|
|
1097
|
-
# label(:
|
|
1098
|
-
# # => <label for="
|
|
1100
|
+
# label(:article, :title)
|
|
1101
|
+
# # => <label for="article_title">Title</label>
|
|
1099
1102
|
#
|
|
1100
1103
|
# You can localize your labels based on model and attribute names.
|
|
1101
1104
|
# For example you can define the following in your locale (e.g. en.yml)
|
|
1102
1105
|
#
|
|
1103
1106
|
# helpers:
|
|
1104
1107
|
# label:
|
|
1105
|
-
#
|
|
1108
|
+
# article:
|
|
1106
1109
|
# body: "Write your entire text here"
|
|
1107
1110
|
#
|
|
1108
1111
|
# Which then will result in
|
|
1109
1112
|
#
|
|
1110
|
-
# label(:
|
|
1111
|
-
# # => <label for="
|
|
1113
|
+
# label(:article, :body)
|
|
1114
|
+
# # => <label for="article_body">Write your entire text here</label>
|
|
1112
1115
|
#
|
|
1113
1116
|
# Localization can also be based purely on the translation of the attribute-name
|
|
1114
1117
|
# (if you are using ActiveRecord):
|
|
1115
1118
|
#
|
|
1116
1119
|
# activerecord:
|
|
1117
1120
|
# attributes:
|
|
1118
|
-
#
|
|
1121
|
+
# article:
|
|
1119
1122
|
# cost: "Total cost"
|
|
1120
1123
|
#
|
|
1121
|
-
#
|
|
1122
|
-
#
|
|
1124
|
+
# <code></code>
|
|
1125
|
+
#
|
|
1126
|
+
# label(:article, :cost)
|
|
1127
|
+
# # => <label for="article_cost">Total cost</label>
|
|
1123
1128
|
#
|
|
1124
|
-
# label(:
|
|
1125
|
-
# # => <label for="
|
|
1129
|
+
# label(:article, :title, "A short title")
|
|
1130
|
+
# # => <label for="article_title">A short title</label>
|
|
1126
1131
|
#
|
|
1127
|
-
# label(:
|
|
1128
|
-
# # => <label for="
|
|
1132
|
+
# label(:article, :title, "A short title", class: "title_label")
|
|
1133
|
+
# # => <label for="article_title" class="title_label">A short title</label>
|
|
1129
1134
|
#
|
|
1130
|
-
# label(:
|
|
1131
|
-
# # => <label for="
|
|
1135
|
+
# label(:article, :privacy, "Public Article", value: "public")
|
|
1136
|
+
# # => <label for="article_privacy_public">Public Article</label>
|
|
1132
1137
|
#
|
|
1133
|
-
# label(:
|
|
1138
|
+
# label(:article, :cost) do |translation|
|
|
1134
1139
|
# content_tag(:span, translation, class: "cost_label")
|
|
1135
1140
|
# end
|
|
1136
|
-
# # => <label for="
|
|
1141
|
+
# # => <label for="article_cost"><span class="cost_label">Total cost</span></label>
|
|
1137
1142
|
#
|
|
1138
|
-
# label(:
|
|
1143
|
+
# label(:article, :cost) do |builder|
|
|
1139
1144
|
# content_tag(:span, builder.translation, class: "cost_label")
|
|
1140
1145
|
# end
|
|
1141
|
-
# # => <label for="
|
|
1146
|
+
# # => <label for="article_cost"><span class="cost_label">Total cost</span></label>
|
|
1142
1147
|
#
|
|
1143
|
-
# label(:
|
|
1148
|
+
# label(:article, :terms) do
|
|
1144
1149
|
# raw('Accept <a href="/terms">Terms</a>.')
|
|
1145
1150
|
# end
|
|
1146
|
-
# # => <label for="
|
|
1151
|
+
# # => <label for="article_terms">Accept <a href="/terms">Terms</a>.</label>
|
|
1147
1152
|
def label(object_name, method, content_or_options = nil, options = nil, &block)
|
|
1148
1153
|
Tags::Label.new(object_name, method, self, content_or_options, options).render(&block)
|
|
1149
1154
|
end
|
|
@@ -1154,14 +1159,14 @@ module ActionView
|
|
|
1154
1159
|
# shown.
|
|
1155
1160
|
#
|
|
1156
1161
|
# ==== Examples
|
|
1157
|
-
# text_field(:
|
|
1158
|
-
# # => <input type="text" id="
|
|
1162
|
+
# text_field(:article, :title, size: 20)
|
|
1163
|
+
# # => <input type="text" id="article_title" name="article[title]" size="20" value="#{@article.title}" />
|
|
1159
1164
|
#
|
|
1160
|
-
# text_field(:
|
|
1161
|
-
# # => <input type="text" id="
|
|
1165
|
+
# text_field(:article, :title, class: "create_input")
|
|
1166
|
+
# # => <input type="text" id="article_title" name="article[title]" value="#{@article.title}" class="create_input" />
|
|
1162
1167
|
#
|
|
1163
|
-
# text_field(:
|
|
1164
|
-
# # => <input type="text" id="
|
|
1168
|
+
# text_field(:article, :title, maxlength: 30, class: "title_input")
|
|
1169
|
+
# # => <input type="text" id="article_title" name="article[title]" maxlength="30" size="30" value="#{@article.title}" class="title_input" />
|
|
1165
1170
|
#
|
|
1166
1171
|
# text_field(:session, :user, onchange: "if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }")
|
|
1167
1172
|
# # => <input type="text" id="session_user" name="session[user]" value="#{@session.user}" onchange="if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }"/>
|
|
@@ -1202,8 +1207,8 @@ module ActionView
|
|
|
1202
1207
|
# hidden_field(:signup, :pass_confirm)
|
|
1203
1208
|
# # => <input type="hidden" id="signup_pass_confirm" name="signup[pass_confirm]" value="#{@signup.pass_confirm}" />
|
|
1204
1209
|
#
|
|
1205
|
-
# hidden_field(:
|
|
1206
|
-
# # => <input type="hidden" id="
|
|
1210
|
+
# hidden_field(:article, :tag_list)
|
|
1211
|
+
# # => <input type="hidden" id="article_tag_list" name="article[tag_list]" value="#{@article.tag_list}" />
|
|
1207
1212
|
#
|
|
1208
1213
|
# hidden_field(:user, :token)
|
|
1209
1214
|
# # => <input type="hidden" id="user_token" name="user[token]" value="#{@user.token}" />
|
|
@@ -1216,7 +1221,7 @@ module ActionView
|
|
|
1216
1221
|
# hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
|
|
1217
1222
|
# shown.
|
|
1218
1223
|
#
|
|
1219
|
-
# Using this method inside a
|
|
1224
|
+
# Using this method inside a #form_with block will set the enclosing form's encoding to <tt>multipart/form-data</tt>.
|
|
1220
1225
|
#
|
|
1221
1226
|
# ==== Options
|
|
1222
1227
|
# * Creates standard HTML attributes for the tag.
|
|
@@ -1229,14 +1234,14 @@ module ActionView
|
|
|
1229
1234
|
# file_field(:user, :avatar)
|
|
1230
1235
|
# # => <input type="file" id="user_avatar" name="user[avatar]" />
|
|
1231
1236
|
#
|
|
1232
|
-
# file_field(:
|
|
1233
|
-
# # => <input type="file" id="
|
|
1237
|
+
# file_field(:article, :image, multiple: true)
|
|
1238
|
+
# # => <input type="file" id="article_image" name="article[image][]" multiple="multiple" />
|
|
1234
1239
|
#
|
|
1235
|
-
# file_field(:
|
|
1236
|
-
# # => <input accept="text/html" type="file" id="
|
|
1240
|
+
# file_field(:article, :attached, accept: 'text/html')
|
|
1241
|
+
# # => <input accept="text/html" type="file" id="article_attached" name="article[attached]" />
|
|
1237
1242
|
#
|
|
1238
|
-
# file_field(:
|
|
1239
|
-
# # => <input type="file" id="
|
|
1243
|
+
# file_field(:article, :image, accept: 'image/png,image/gif,image/jpeg')
|
|
1244
|
+
# # => <input type="file" id="article_image" name="article[image]" accept="image/png,image/gif,image/jpeg" />
|
|
1240
1245
|
#
|
|
1241
1246
|
# file_field(:attachment, :file, class: 'file_input')
|
|
1242
1247
|
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
|
|
@@ -1251,28 +1256,29 @@ module ActionView
|
|
|
1251
1256
|
# hash with +options+.
|
|
1252
1257
|
#
|
|
1253
1258
|
# ==== Examples
|
|
1254
|
-
#
|
|
1255
|
-
# # => <textarea cols="20" rows="40" id="
|
|
1256
|
-
# # #{@
|
|
1259
|
+
# textarea(:article, :body, cols: 20, rows: 40)
|
|
1260
|
+
# # => <textarea cols="20" rows="40" id="article_body" name="article[body]">
|
|
1261
|
+
# # #{@article.body}
|
|
1257
1262
|
# # </textarea>
|
|
1258
1263
|
#
|
|
1259
|
-
#
|
|
1264
|
+
# textarea(:comment, :text, size: "20x30")
|
|
1260
1265
|
# # => <textarea cols="20" rows="30" id="comment_text" name="comment[text]">
|
|
1261
1266
|
# # #{@comment.text}
|
|
1262
1267
|
# # </textarea>
|
|
1263
1268
|
#
|
|
1264
|
-
#
|
|
1269
|
+
# textarea(:application, :notes, cols: 40, rows: 15, class: 'app_input')
|
|
1265
1270
|
# # => <textarea cols="40" rows="15" id="application_notes" name="application[notes]" class="app_input">
|
|
1266
1271
|
# # #{@application.notes}
|
|
1267
1272
|
# # </textarea>
|
|
1268
1273
|
#
|
|
1269
|
-
#
|
|
1274
|
+
# textarea(:entry, :body, size: "20x20", disabled: 'disabled')
|
|
1270
1275
|
# # => <textarea cols="20" rows="20" id="entry_body" name="entry[body]" disabled="disabled">
|
|
1271
1276
|
# # #{@entry.body}
|
|
1272
1277
|
# # </textarea>
|
|
1273
|
-
def
|
|
1278
|
+
def textarea(object_name, method, options = {})
|
|
1274
1279
|
Tags::TextArea.new(object_name, method, self, options).render
|
|
1275
1280
|
end
|
|
1281
|
+
alias_method :text_area, :textarea
|
|
1276
1282
|
|
|
1277
1283
|
# Returns a checkbox tag tailored for accessing a specified attribute (identified by +method+) on an object
|
|
1278
1284
|
# assigned to the template (identified by +object+). This object must be an instance object (@object) and not a local object.
|
|
@@ -1312,7 +1318,7 @@ module ActionView
|
|
|
1312
1318
|
# within an array-like parameter, as in
|
|
1313
1319
|
#
|
|
1314
1320
|
# <%= fields_for "project[invoice_attributes][]", invoice, index: nil do |form| %>
|
|
1315
|
-
# <%= form.
|
|
1321
|
+
# <%= form.checkbox :paid %>
|
|
1316
1322
|
# ...
|
|
1317
1323
|
# <% end %>
|
|
1318
1324
|
#
|
|
@@ -1320,27 +1326,28 @@ module ActionView
|
|
|
1320
1326
|
# the elements of the array. For each item with a checked check box you
|
|
1321
1327
|
# get an extra ghost item with only that attribute, assigned to "0".
|
|
1322
1328
|
#
|
|
1323
|
-
# In that case it is preferable to either use
|
|
1329
|
+
# In that case it is preferable to either use FormTagHelper#checkbox_tag or to use
|
|
1324
1330
|
# hashes instead of arrays.
|
|
1325
1331
|
#
|
|
1326
1332
|
# ==== Examples
|
|
1327
1333
|
#
|
|
1328
|
-
# # Let's say that @
|
|
1329
|
-
#
|
|
1330
|
-
# # => <input name="
|
|
1331
|
-
# # <input checked="checked" type="checkbox" id="
|
|
1334
|
+
# # Let's say that @article.validated? is 1:
|
|
1335
|
+
# checkbox("article", "validated")
|
|
1336
|
+
# # => <input name="article[validated]" type="hidden" value="0" />
|
|
1337
|
+
# # <input checked="checked" type="checkbox" id="article_validated" name="article[validated]" value="1" />
|
|
1332
1338
|
#
|
|
1333
1339
|
# # Let's say that @puppy.gooddog is "no":
|
|
1334
|
-
#
|
|
1340
|
+
# checkbox("puppy", "gooddog", {}, "yes", "no")
|
|
1335
1341
|
# # => <input name="puppy[gooddog]" type="hidden" value="no" />
|
|
1336
1342
|
# # <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
|
|
1337
1343
|
#
|
|
1338
|
-
#
|
|
1344
|
+
# checkbox("eula", "accepted", { class: 'eula_check' }, "yes", "no")
|
|
1339
1345
|
# # => <input name="eula[accepted]" type="hidden" value="no" />
|
|
1340
1346
|
# # <input type="checkbox" class="eula_check" id="eula_accepted" name="eula[accepted]" value="yes" />
|
|
1341
|
-
def
|
|
1347
|
+
def checkbox(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
|
|
1342
1348
|
Tags::CheckBox.new(object_name, method, self, checked_value, unchecked_value, options).render
|
|
1343
1349
|
end
|
|
1350
|
+
alias_method :check_box, :checkbox
|
|
1344
1351
|
|
|
1345
1352
|
# Returns a radio button tag for accessing a specified attribute (identified by +method+) on an object
|
|
1346
1353
|
# assigned to the template (identified by +object+). If the current value of +method+ is +tag_value+ the
|
|
@@ -1349,11 +1356,11 @@ module ActionView
|
|
|
1349
1356
|
# To force the radio button to be checked pass <tt>checked: true</tt> in the
|
|
1350
1357
|
# +options+ hash. You may pass HTML options there as well.
|
|
1351
1358
|
#
|
|
1352
|
-
# # Let's say that @
|
|
1353
|
-
# radio_button("
|
|
1354
|
-
# radio_button("
|
|
1355
|
-
# # => <input type="radio" id="
|
|
1356
|
-
# # <input type="radio" id="
|
|
1359
|
+
# # Let's say that @article.category returns "rails":
|
|
1360
|
+
# radio_button("article", "category", "rails")
|
|
1361
|
+
# radio_button("article", "category", "java")
|
|
1362
|
+
# # => <input type="radio" id="article_category_rails" name="article[category]" value="rails" checked="checked" />
|
|
1363
|
+
# # <input type="radio" id="article_category_java" name="article[category]" value="java" />
|
|
1357
1364
|
#
|
|
1358
1365
|
# # Let's say that @user.receive_newsletter returns "no":
|
|
1359
1366
|
# radio_button("user", "receive_newsletter", "yes")
|
|
@@ -1625,17 +1632,17 @@ module ActionView
|
|
|
1625
1632
|
#
|
|
1626
1633
|
# A +FormBuilder+ object is associated with a particular model object and
|
|
1627
1634
|
# allows you to generate fields associated with the model object. The
|
|
1628
|
-
# +FormBuilder+ object is yielded when using
|
|
1635
|
+
# +FormBuilder+ object is yielded when using #form_with or #fields_for.
|
|
1629
1636
|
# For example:
|
|
1630
1637
|
#
|
|
1631
|
-
# <%=
|
|
1638
|
+
# <%= form_with model: @person do |person_form| %>
|
|
1632
1639
|
# Name: <%= person_form.text_field :name %>
|
|
1633
|
-
# Admin: <%= person_form.
|
|
1640
|
+
# Admin: <%= person_form.checkbox :admin %>
|
|
1634
1641
|
# <% end %>
|
|
1635
1642
|
#
|
|
1636
1643
|
# In the above block, a +FormBuilder+ object is yielded as the
|
|
1637
1644
|
# +person_form+ variable. This allows you to generate the +text_field+
|
|
1638
|
-
# and +
|
|
1645
|
+
# and +checkbox+ fields by specifying their eponymous methods, which
|
|
1639
1646
|
# modify the underlying template and associates the <tt>@person</tt> model object
|
|
1640
1647
|
# with the form.
|
|
1641
1648
|
#
|
|
@@ -1664,7 +1671,7 @@ module ActionView
|
|
|
1664
1671
|
#
|
|
1665
1672
|
# The +div_radio_button+ code from above can now be used as follows:
|
|
1666
1673
|
#
|
|
1667
|
-
# <%=
|
|
1674
|
+
# <%= form_with model: @person, :builder => MyFormBuilder do |f| %>
|
|
1668
1675
|
# I am a child: <%= f.div_radio_button(:admin, "child") %>
|
|
1669
1676
|
# I am an adult: <%= f.div_radio_button(:admin, "adult") %>
|
|
1670
1677
|
# <% end -%>
|
|
@@ -1677,7 +1684,7 @@ module ActionView
|
|
|
1677
1684
|
# The methods which wrap a form helper call.
|
|
1678
1685
|
class_attribute :field_helpers, default: [
|
|
1679
1686
|
:fields_for, :fields, :label, :text_field, :password_field,
|
|
1680
|
-
:hidden_field, :file_field, :
|
|
1687
|
+
:hidden_field, :file_field, :textarea, :checkbox,
|
|
1681
1688
|
:radio_button, :color_field, :search_field,
|
|
1682
1689
|
:telephone_field, :phone_field, :date_field,
|
|
1683
1690
|
:time_field, :datetime_field, :datetime_local_field,
|
|
@@ -1734,7 +1741,7 @@ module ActionView
|
|
|
1734
1741
|
#
|
|
1735
1742
|
# return the <tt><form></tt> element's <tt>id</tt> attribute.
|
|
1736
1743
|
#
|
|
1737
|
-
# <%=
|
|
1744
|
+
# <%= form_with model: @article do |f| %>
|
|
1738
1745
|
# <%# ... %>
|
|
1739
1746
|
#
|
|
1740
1747
|
# <% content_for :sticky_footer do %>
|
|
@@ -1756,16 +1763,16 @@ module ActionView
|
|
|
1756
1763
|
# Return the value generated by the <tt>FormBuilder</tt> for the given
|
|
1757
1764
|
# attribute name.
|
|
1758
1765
|
#
|
|
1759
|
-
# <%=
|
|
1766
|
+
# <%= form_with model: @article do |f| %>
|
|
1760
1767
|
# <%= f.label :title %>
|
|
1761
1768
|
# <%= f.text_field :title, aria: { describedby: f.field_id(:title, :error) } %>
|
|
1762
1769
|
# <%= tag.span("is blank", id: f.field_id(:title, :error) %>
|
|
1763
1770
|
# <% end %>
|
|
1764
1771
|
#
|
|
1765
1772
|
# In the example above, the <tt><input type="text"></tt> element built by
|
|
1766
|
-
# the call to
|
|
1773
|
+
# the call to #text_field declares an
|
|
1767
1774
|
# <tt>aria-describedby</tt> attribute referencing the <tt><span></tt>
|
|
1768
|
-
# element, sharing a common <tt>id</tt> root (<tt>
|
|
1775
|
+
# element, sharing a common <tt>id</tt> root (<tt>article_title</tt>, in this
|
|
1769
1776
|
# case).
|
|
1770
1777
|
def field_id(method, *suffixes, namespace: @options[:namespace], index: @options[:index])
|
|
1771
1778
|
@template.field_id(@object_name, method, *suffixes, namespace: namespace, index: index)
|
|
@@ -1777,14 +1784,14 @@ module ActionView
|
|
|
1777
1784
|
# Return the value generated by the <tt>FormBuilder</tt> for the given
|
|
1778
1785
|
# attribute name.
|
|
1779
1786
|
#
|
|
1780
|
-
# <%=
|
|
1787
|
+
# <%= form_with model: @article do |f| %>
|
|
1781
1788
|
# <%= f.text_field :title, name: f.field_name(:title, :subtitle) %>
|
|
1782
|
-
# <%# => <input type="text" name="
|
|
1789
|
+
# <%# => <input type="text" name="article[title][subtitle]"> %>
|
|
1783
1790
|
# <% end %>
|
|
1784
1791
|
#
|
|
1785
|
-
# <%=
|
|
1792
|
+
# <%= form_with model: @article do |f| %>
|
|
1786
1793
|
# <%= f.text_field :tag, name: f.field_name(:tag, multiple: true) %>
|
|
1787
|
-
# <%# => <input type="text" name="
|
|
1794
|
+
# <%# => <input type="text" name="article[tag][]"> %>
|
|
1788
1795
|
# <% end %>
|
|
1789
1796
|
#
|
|
1790
1797
|
def field_name(method, *methods, multiple: false, index: @options[:index])
|
|
@@ -1820,14 +1827,14 @@ module ActionView
|
|
|
1820
1827
|
# Please refer to the documentation of the base helper for details.
|
|
1821
1828
|
|
|
1822
1829
|
##
|
|
1823
|
-
# :method:
|
|
1830
|
+
# :method: textarea
|
|
1824
1831
|
#
|
|
1825
|
-
# :call-seq:
|
|
1832
|
+
# :call-seq: textarea(method, options = {})
|
|
1826
1833
|
#
|
|
1827
|
-
# Wraps ActionView::Helpers::FormHelper#
|
|
1834
|
+
# Wraps ActionView::Helpers::FormHelper#textarea for form builders:
|
|
1828
1835
|
#
|
|
1829
1836
|
# <%= form_with model: @user do |f| %>
|
|
1830
|
-
# <%= f.
|
|
1837
|
+
# <%= f.textarea :detail %>
|
|
1831
1838
|
# <% end %>
|
|
1832
1839
|
#
|
|
1833
1840
|
# Please refer to the documentation of the base helper for details.
|
|
@@ -2014,40 +2021,40 @@ module ActionView
|
|
|
2014
2021
|
#
|
|
2015
2022
|
# Please refer to the documentation of the base helper for details.
|
|
2016
2023
|
|
|
2017
|
-
(
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
end
|
|
2026
|
-
RUBY_EVAL
|
|
2024
|
+
ActiveSupport::CodeGenerator.batch(self, __FILE__, __LINE__) do |code_generator|
|
|
2025
|
+
(field_helpers - [:label, :checkbox, :radio_button, :fields_for, :fields, :hidden_field, :file_field]).each do |selector|
|
|
2026
|
+
code_generator.class_eval do |batch|
|
|
2027
|
+
batch <<
|
|
2028
|
+
"def #{selector}(method, options = {})" <<
|
|
2029
|
+
" @template.#{selector}(@object_name, method, objectify_options(options))" <<
|
|
2030
|
+
"end"
|
|
2031
|
+
end
|
|
2032
|
+
end
|
|
2027
2033
|
end
|
|
2034
|
+
alias_method :text_area, :textarea
|
|
2028
2035
|
|
|
2029
|
-
# Creates a scope around a specific model object like
|
|
2030
|
-
# doesn't create the form tags themselves. This makes fields_for
|
|
2031
|
-
# for specifying additional model objects in the same form.
|
|
2036
|
+
# Creates a scope around a specific model object like #form_with, but
|
|
2037
|
+
# doesn't create the form tags themselves. This makes +fields_for+
|
|
2038
|
+
# suitable for specifying additional model objects in the same form.
|
|
2032
2039
|
#
|
|
2033
|
-
# Although the usage and purpose of +fields_for+ is similar to
|
|
2034
|
-
# its method signature is slightly different. Like
|
|
2040
|
+
# Although the usage and purpose of +fields_for+ is similar to #form_with's,
|
|
2041
|
+
# its method signature is slightly different. Like #form_with, it yields
|
|
2035
2042
|
# a FormBuilder object associated with a particular model object to a block,
|
|
2036
2043
|
# and within the block allows methods to be called on the builder to
|
|
2037
2044
|
# generate fields associated with the model object. Fields may reflect
|
|
2038
2045
|
# a model object in two ways - how they are named (hence how submitted
|
|
2039
2046
|
# values appear within the +params+ hash in the controller) and what
|
|
2040
|
-
# default values are shown when the form
|
|
2041
|
-
#
|
|
2047
|
+
# default values are shown when the form fields are first displayed.
|
|
2048
|
+
# In order for both of these features to be specified independently,
|
|
2042
2049
|
# both an object name (represented by either a symbol or string) and the
|
|
2043
2050
|
# object itself can be passed to the method separately -
|
|
2044
2051
|
#
|
|
2045
|
-
# <%=
|
|
2052
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2046
2053
|
# First name: <%= person_form.text_field :first_name %>
|
|
2047
2054
|
# Last name : <%= person_form.text_field :last_name %>
|
|
2048
2055
|
#
|
|
2049
2056
|
# <%= fields_for :permission, @person.permission do |permission_fields| %>
|
|
2050
|
-
# Admin? : <%= permission_fields.
|
|
2057
|
+
# Admin? : <%= permission_fields.checkbox :admin %>
|
|
2051
2058
|
# <% end %>
|
|
2052
2059
|
#
|
|
2053
2060
|
# <%= person_form.submit %>
|
|
@@ -2064,7 +2071,7 @@ module ActionView
|
|
|
2064
2071
|
# object to +fields_for+ -
|
|
2065
2072
|
#
|
|
2066
2073
|
# <%= fields_for :permission do |permission_fields| %>
|
|
2067
|
-
# Admin?: <%= permission_fields.
|
|
2074
|
+
# Admin?: <%= permission_fields.checkbox :admin %>
|
|
2068
2075
|
# <% end %>
|
|
2069
2076
|
#
|
|
2070
2077
|
# ...in which case, if <tt>:permission</tt> also happens to be the name of an
|
|
@@ -2076,7 +2083,7 @@ module ActionView
|
|
|
2076
2083
|
# name has been omitted) -
|
|
2077
2084
|
#
|
|
2078
2085
|
# <%= fields_for @person.permission do |permission_fields| %>
|
|
2079
|
-
# Admin?: <%= permission_fields.
|
|
2086
|
+
# Admin?: <%= permission_fields.checkbox :admin %>
|
|
2080
2087
|
# <% end %>
|
|
2081
2088
|
#
|
|
2082
2089
|
# and +fields_for+ will derive the required name of the field from the
|
|
@@ -2091,10 +2098,10 @@ module ActionView
|
|
|
2091
2098
|
# name and value parameters are provided and the provided value has the shape of an
|
|
2092
2099
|
# option Hash. To remove the ambiguity, explicitly pass an option Hash, even if empty.
|
|
2093
2100
|
#
|
|
2094
|
-
# <%=
|
|
2101
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2095
2102
|
# ...
|
|
2096
2103
|
# <%= fields_for :permission, @person.permission, {} do |permission_fields| %>
|
|
2097
|
-
# Admin?: <%=
|
|
2104
|
+
# Admin?: <%= checkbox_tag permission_fields.field_name(:admin), @person.permission[:admin] %>
|
|
2098
2105
|
# <% end %>
|
|
2099
2106
|
# ...
|
|
2100
2107
|
# <% end %>
|
|
@@ -2102,7 +2109,7 @@ module ActionView
|
|
|
2102
2109
|
# === Nested Attributes Examples
|
|
2103
2110
|
#
|
|
2104
2111
|
# When the object belonging to the current scope has a nested attribute
|
|
2105
|
-
# writer for a certain attribute, fields_for will yield a new scope
|
|
2112
|
+
# writer for a certain attribute, +fields_for+ will yield a new scope
|
|
2106
2113
|
# for that attribute. This allows you to create forms that set or change
|
|
2107
2114
|
# the attributes of a parent object and its associations in one go.
|
|
2108
2115
|
#
|
|
@@ -2133,9 +2140,9 @@ module ActionView
|
|
|
2133
2140
|
# end
|
|
2134
2141
|
# end
|
|
2135
2142
|
#
|
|
2136
|
-
# This model can now be used with a nested fields_for
|
|
2143
|
+
# This model can now be used with a nested +fields_for+, like so:
|
|
2137
2144
|
#
|
|
2138
|
-
# <%=
|
|
2145
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2139
2146
|
# ...
|
|
2140
2147
|
# <%= person_form.fields_for :address do |address_fields| %>
|
|
2141
2148
|
# Street : <%= address_fields.text_field :street %>
|
|
@@ -2165,11 +2172,11 @@ module ActionView
|
|
|
2165
2172
|
# with a value that evaluates to +true+, you will destroy the associated
|
|
2166
2173
|
# model (e.g. 1, '1', true, or 'true'):
|
|
2167
2174
|
#
|
|
2168
|
-
# <%=
|
|
2175
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2169
2176
|
# ...
|
|
2170
2177
|
# <%= person_form.fields_for :address do |address_fields| %>
|
|
2171
2178
|
# ...
|
|
2172
|
-
# Delete: <%= address_fields.
|
|
2179
|
+
# Delete: <%= address_fields.checkbox :_destroy %>
|
|
2173
2180
|
# <% end %>
|
|
2174
2181
|
# ...
|
|
2175
2182
|
# <% end %>
|
|
@@ -2191,7 +2198,7 @@ module ActionView
|
|
|
2191
2198
|
# end
|
|
2192
2199
|
#
|
|
2193
2200
|
# Note that the <tt>projects_attributes=</tt> writer method is in fact
|
|
2194
|
-
# required for fields_for to correctly identify <tt>:projects</tt> as a
|
|
2201
|
+
# required for +fields_for+ to correctly identify <tt>:projects</tt> as a
|
|
2195
2202
|
# collection, and the correct indices to be set in the form markup.
|
|
2196
2203
|
#
|
|
2197
2204
|
# When projects is already an association on Person you can use
|
|
@@ -2202,11 +2209,11 @@ module ActionView
|
|
|
2202
2209
|
# accepts_nested_attributes_for :projects
|
|
2203
2210
|
# end
|
|
2204
2211
|
#
|
|
2205
|
-
# This model can now be used with a nested fields_for
|
|
2206
|
-
# the nested fields_for call will be repeated for each instance in the
|
|
2212
|
+
# This model can now be used with a nested +fields_for+. The block given to
|
|
2213
|
+
# the nested +fields_for+ call will be repeated for each instance in the
|
|
2207
2214
|
# collection:
|
|
2208
2215
|
#
|
|
2209
|
-
# <%=
|
|
2216
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2210
2217
|
# ...
|
|
2211
2218
|
# <%= person_form.fields_for :projects do |project_fields| %>
|
|
2212
2219
|
# <% if project_fields.object.active? %>
|
|
@@ -2218,7 +2225,7 @@ module ActionView
|
|
|
2218
2225
|
#
|
|
2219
2226
|
# It's also possible to specify the instance to be used:
|
|
2220
2227
|
#
|
|
2221
|
-
# <%=
|
|
2228
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2222
2229
|
# ...
|
|
2223
2230
|
# <% @person.projects.each do |project| %>
|
|
2224
2231
|
# <% if project.active? %>
|
|
@@ -2232,7 +2239,7 @@ module ActionView
|
|
|
2232
2239
|
#
|
|
2233
2240
|
# Or a collection to be used:
|
|
2234
2241
|
#
|
|
2235
|
-
# <%=
|
|
2242
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2236
2243
|
# ...
|
|
2237
2244
|
# <%= person_form.fields_for :projects, @active_projects do |project_fields| %>
|
|
2238
2245
|
# Name: <%= project_fields.text_field :name %>
|
|
@@ -2254,10 +2261,10 @@ module ActionView
|
|
|
2254
2261
|
# parameter with a value that evaluates to +true+
|
|
2255
2262
|
# (e.g. 1, '1', true, or 'true'):
|
|
2256
2263
|
#
|
|
2257
|
-
# <%=
|
|
2264
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2258
2265
|
# ...
|
|
2259
2266
|
# <%= person_form.fields_for :projects do |project_fields| %>
|
|
2260
|
-
# Delete: <%= project_fields.
|
|
2267
|
+
# Delete: <%= project_fields.checkbox :_destroy %>
|
|
2261
2268
|
# <% end %>
|
|
2262
2269
|
# ...
|
|
2263
2270
|
# <% end %>
|
|
@@ -2266,7 +2273,7 @@ module ActionView
|
|
|
2266
2273
|
# object in the array. For this purpose, the <tt>index</tt> method
|
|
2267
2274
|
# is available in the FormBuilder object.
|
|
2268
2275
|
#
|
|
2269
|
-
# <%=
|
|
2276
|
+
# <%= form_with model: @person do |person_form| %>
|
|
2270
2277
|
# ...
|
|
2271
2278
|
# <%= person_form.fields_for :projects do |project_fields| %>
|
|
2272
2279
|
# Project #<%= project_fields.index %>
|
|
@@ -2275,10 +2282,10 @@ module ActionView
|
|
|
2275
2282
|
# ...
|
|
2276
2283
|
# <% end %>
|
|
2277
2284
|
#
|
|
2278
|
-
# Note that fields_for will automatically generate a hidden field
|
|
2285
|
+
# Note that +fields_for+ will automatically generate a hidden field
|
|
2279
2286
|
# to store the ID of the record. There are circumstances where this
|
|
2280
2287
|
# hidden field is not needed and you can pass <tt>include_id: false</tt>
|
|
2281
|
-
# to prevent fields_for from rendering it automatically.
|
|
2288
|
+
# to prevent +fields_for+ from rendering it automatically.
|
|
2282
2289
|
def fields_for(record_name, record_object = nil, fields_options = nil, &block)
|
|
2283
2290
|
fields_options, record_object = record_object, nil if fields_options.nil? && record_object.is_a?(Hash) && record_object.extractable_options?
|
|
2284
2291
|
fields_options ||= {}
|
|
@@ -2335,50 +2342,52 @@ module ActionView
|
|
|
2335
2342
|
#
|
|
2336
2343
|
# ==== Examples
|
|
2337
2344
|
# label(:title)
|
|
2338
|
-
# # => <label for="
|
|
2345
|
+
# # => <label for="article_title">Title</label>
|
|
2339
2346
|
#
|
|
2340
2347
|
# You can localize your labels based on model and attribute names.
|
|
2341
2348
|
# For example you can define the following in your locale (e.g. en.yml)
|
|
2342
2349
|
#
|
|
2343
2350
|
# helpers:
|
|
2344
2351
|
# label:
|
|
2345
|
-
#
|
|
2352
|
+
# article:
|
|
2346
2353
|
# body: "Write your entire text here"
|
|
2347
2354
|
#
|
|
2348
2355
|
# Which then will result in
|
|
2349
2356
|
#
|
|
2350
2357
|
# label(:body)
|
|
2351
|
-
# # => <label for="
|
|
2358
|
+
# # => <label for="article_body">Write your entire text here</label>
|
|
2352
2359
|
#
|
|
2353
2360
|
# Localization can also be based purely on the translation of the attribute-name
|
|
2354
2361
|
# (if you are using ActiveRecord):
|
|
2355
2362
|
#
|
|
2356
2363
|
# activerecord:
|
|
2357
2364
|
# attributes:
|
|
2358
|
-
#
|
|
2365
|
+
# article:
|
|
2359
2366
|
# cost: "Total cost"
|
|
2360
2367
|
#
|
|
2368
|
+
# <code></code>
|
|
2369
|
+
#
|
|
2361
2370
|
# label(:cost)
|
|
2362
|
-
# # => <label for="
|
|
2371
|
+
# # => <label for="article_cost">Total cost</label>
|
|
2363
2372
|
#
|
|
2364
2373
|
# label(:title, "A short title")
|
|
2365
|
-
# # => <label for="
|
|
2374
|
+
# # => <label for="article_title">A short title</label>
|
|
2366
2375
|
#
|
|
2367
2376
|
# label(:title, "A short title", class: "title_label")
|
|
2368
|
-
# # => <label for="
|
|
2377
|
+
# # => <label for="article_title" class="title_label">A short title</label>
|
|
2369
2378
|
#
|
|
2370
|
-
# label(:privacy, "Public
|
|
2371
|
-
# # => <label for="
|
|
2379
|
+
# label(:privacy, "Public Article", value: "public")
|
|
2380
|
+
# # => <label for="article_privacy_public">Public Article</label>
|
|
2372
2381
|
#
|
|
2373
2382
|
# label(:cost) do |translation|
|
|
2374
2383
|
# content_tag(:span, translation, class: "cost_label")
|
|
2375
2384
|
# end
|
|
2376
|
-
# # => <label for="
|
|
2385
|
+
# # => <label for="article_cost"><span class="cost_label">Total cost</span></label>
|
|
2377
2386
|
#
|
|
2378
2387
|
# label(:cost) do |builder|
|
|
2379
2388
|
# content_tag(:span, builder.translation, class: "cost_label")
|
|
2380
2389
|
# end
|
|
2381
|
-
# # => <label for="
|
|
2390
|
+
# # => <label for="article_cost"><span class="cost_label">Total cost</span></label>
|
|
2382
2391
|
#
|
|
2383
2392
|
# label(:cost) do |builder|
|
|
2384
2393
|
# content_tag(:span, builder.translation, class: [
|
|
@@ -2386,12 +2395,12 @@ module ActionView
|
|
|
2386
2395
|
# ("error_label" if builder.object.errors.include?(:cost))
|
|
2387
2396
|
# ])
|
|
2388
2397
|
# end
|
|
2389
|
-
# # => <label for="
|
|
2398
|
+
# # => <label for="article_cost"><span class="cost_label error_label">Total cost</span></label>
|
|
2390
2399
|
#
|
|
2391
2400
|
# label(:terms) do
|
|
2392
2401
|
# raw('Accept <a href="/terms">Terms</a>.')
|
|
2393
2402
|
# end
|
|
2394
|
-
# # => <label for="
|
|
2403
|
+
# # => <label for="article_terms">Accept <a href="/terms">Terms</a>.</label>
|
|
2395
2404
|
def label(method, text = nil, options = {}, &block)
|
|
2396
2405
|
@template.label(@object_name, method, text, objectify_options(options), &block)
|
|
2397
2406
|
end
|
|
@@ -2434,7 +2443,7 @@ module ActionView
|
|
|
2434
2443
|
# within an array-like parameter, as in
|
|
2435
2444
|
#
|
|
2436
2445
|
# <%= fields_for "project[invoice_attributes][]", invoice, index: nil do |form| %>
|
|
2437
|
-
# <%= form.
|
|
2446
|
+
# <%= form.checkbox :paid %>
|
|
2438
2447
|
# ...
|
|
2439
2448
|
# <% end %>
|
|
2440
2449
|
#
|
|
@@ -2442,28 +2451,29 @@ module ActionView
|
|
|
2442
2451
|
# the elements of the array. For each item with a checked check box you
|
|
2443
2452
|
# get an extra ghost item with only that attribute, assigned to "0".
|
|
2444
2453
|
#
|
|
2445
|
-
# In that case it is preferable to either use
|
|
2454
|
+
# In that case it is preferable to either use FormTagHelper#checkbox_tag or to use
|
|
2446
2455
|
# hashes instead of arrays.
|
|
2447
2456
|
#
|
|
2448
2457
|
# ==== Examples
|
|
2449
2458
|
#
|
|
2450
|
-
# # Let's say that @
|
|
2451
|
-
#
|
|
2452
|
-
# # => <input name="
|
|
2453
|
-
# # <input checked="checked" type="checkbox" id="
|
|
2459
|
+
# # Let's say that @article.validated? is 1:
|
|
2460
|
+
# checkbox("validated")
|
|
2461
|
+
# # => <input name="article[validated]" type="hidden" value="0" />
|
|
2462
|
+
# # <input checked="checked" type="checkbox" id="article_validated" name="article[validated]" value="1" />
|
|
2454
2463
|
#
|
|
2455
2464
|
# # Let's say that @puppy.gooddog is "no":
|
|
2456
|
-
#
|
|
2465
|
+
# checkbox("gooddog", {}, "yes", "no")
|
|
2457
2466
|
# # => <input name="puppy[gooddog]" type="hidden" value="no" />
|
|
2458
2467
|
# # <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
|
|
2459
2468
|
#
|
|
2460
2469
|
# # Let's say that @eula.accepted is "no":
|
|
2461
|
-
#
|
|
2470
|
+
# checkbox("accepted", { class: 'eula_check' }, "yes", "no")
|
|
2462
2471
|
# # => <input name="eula[accepted]" type="hidden" value="no" />
|
|
2463
2472
|
# # <input type="checkbox" class="eula_check" id="eula_accepted" name="eula[accepted]" value="yes" />
|
|
2464
|
-
def
|
|
2465
|
-
@template.
|
|
2473
|
+
def checkbox(method, options = {}, checked_value = "1", unchecked_value = "0")
|
|
2474
|
+
@template.checkbox(@object_name, method, objectify_options(options), checked_value, unchecked_value)
|
|
2466
2475
|
end
|
|
2476
|
+
alias_method :check_box, :checkbox
|
|
2467
2477
|
|
|
2468
2478
|
# Returns a radio button tag for accessing a specified attribute (identified by +method+) on an object
|
|
2469
2479
|
# assigned to the template (identified by +object+). If the current value of +method+ is +tag_value+ the
|
|
@@ -2472,11 +2482,11 @@ module ActionView
|
|
|
2472
2482
|
# To force the radio button to be checked pass <tt>checked: true</tt> in the
|
|
2473
2483
|
# +options+ hash. You may pass HTML options there as well.
|
|
2474
2484
|
#
|
|
2475
|
-
# # Let's say that @
|
|
2485
|
+
# # Let's say that @article.category returns "rails":
|
|
2476
2486
|
# radio_button("category", "rails")
|
|
2477
2487
|
# radio_button("category", "java")
|
|
2478
|
-
# # => <input type="radio" id="
|
|
2479
|
-
# # <input type="radio" id="
|
|
2488
|
+
# # => <input type="radio" id="article_category_rails" name="article[category]" value="rails" checked="checked" />
|
|
2489
|
+
# # <input type="radio" id="article_category_java" name="article[category]" value="java" />
|
|
2480
2490
|
#
|
|
2481
2491
|
# # Let's say that @user.receive_newsletter returns "no":
|
|
2482
2492
|
# radio_button("receive_newsletter", "yes")
|
|
@@ -2497,9 +2507,9 @@ module ActionView
|
|
|
2497
2507
|
# hidden_field(:pass_confirm)
|
|
2498
2508
|
# # => <input type="hidden" id="signup_pass_confirm" name="signup[pass_confirm]" value="true" />
|
|
2499
2509
|
#
|
|
2500
|
-
# # Let's say that @
|
|
2510
|
+
# # Let's say that @article.tag_list returns "blog, ruby":
|
|
2501
2511
|
# hidden_field(:tag_list)
|
|
2502
|
-
# # => <input type="hidden" id="
|
|
2512
|
+
# # => <input type="hidden" id="article_tag_list" name="article[tag_list]" value="blog, ruby" />
|
|
2503
2513
|
#
|
|
2504
2514
|
# # Let's say that @user.token returns "abcde":
|
|
2505
2515
|
# hidden_field(:token)
|
|
@@ -2515,7 +2525,7 @@ module ActionView
|
|
|
2515
2525
|
# hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
|
|
2516
2526
|
# shown.
|
|
2517
2527
|
#
|
|
2518
|
-
# Using this method inside a
|
|
2528
|
+
# Using this method inside a #form_with block will set the enclosing form's encoding to <tt>multipart/form-data</tt>.
|
|
2519
2529
|
#
|
|
2520
2530
|
# ==== Options
|
|
2521
2531
|
# * Creates standard HTML attributes for the tag.
|
|
@@ -2529,17 +2539,17 @@ module ActionView
|
|
|
2529
2539
|
# file_field(:avatar)
|
|
2530
2540
|
# # => <input type="file" id="user_avatar" name="user[avatar]" />
|
|
2531
2541
|
#
|
|
2532
|
-
# # Let's say that @
|
|
2542
|
+
# # Let's say that @article has image:
|
|
2533
2543
|
# file_field(:image, :multiple => true)
|
|
2534
|
-
# # => <input type="file" id="
|
|
2544
|
+
# # => <input type="file" id="article_image" name="article[image][]" multiple="multiple" />
|
|
2535
2545
|
#
|
|
2536
|
-
# # Let's say that @
|
|
2546
|
+
# # Let's say that @article has attached:
|
|
2537
2547
|
# file_field(:attached, accept: 'text/html')
|
|
2538
|
-
# # => <input accept="text/html" type="file" id="
|
|
2548
|
+
# # => <input accept="text/html" type="file" id="article_attached" name="article[attached]" />
|
|
2539
2549
|
#
|
|
2540
|
-
# # Let's say that @
|
|
2550
|
+
# # Let's say that @article has image:
|
|
2541
2551
|
# file_field(:image, accept: 'image/png,image/gif,image/jpeg')
|
|
2542
|
-
# # => <input type="file" id="
|
|
2552
|
+
# # => <input type="file" id="article_image" name="article[image]" accept="image/png,image/gif,image/jpeg" />
|
|
2543
2553
|
#
|
|
2544
2554
|
# # Let's say that @attachment has file:
|
|
2545
2555
|
# file_field(:file, class: 'file_input')
|
|
@@ -2552,12 +2562,12 @@ module ActionView
|
|
|
2552
2562
|
# Add the submit button for the given form. When no value is given, it checks
|
|
2553
2563
|
# if the object is a new resource or not to create the proper label:
|
|
2554
2564
|
#
|
|
2555
|
-
# <%=
|
|
2565
|
+
# <%= form_with model: @article do |f| %>
|
|
2556
2566
|
# <%= f.submit %>
|
|
2557
2567
|
# <% end %>
|
|
2558
2568
|
#
|
|
2559
|
-
# In the example above, if <tt>@
|
|
2560
|
-
# submit button label; otherwise, it uses "Update
|
|
2569
|
+
# In the example above, if <tt>@article</tt> is a new record, it will use "Create Article" as
|
|
2570
|
+
# submit button label; otherwise, it uses "Update Article".
|
|
2561
2571
|
#
|
|
2562
2572
|
# Those labels can be customized using I18n under the +helpers.submit+ key and using
|
|
2563
2573
|
# <tt>%{model}</tt> for translation interpolation:
|
|
@@ -2573,7 +2583,7 @@ module ActionView
|
|
|
2573
2583
|
# en:
|
|
2574
2584
|
# helpers:
|
|
2575
2585
|
# submit:
|
|
2576
|
-
#
|
|
2586
|
+
# article:
|
|
2577
2587
|
# create: "Add %{model}"
|
|
2578
2588
|
#
|
|
2579
2589
|
def submit(value = nil, options = {})
|
|
@@ -2585,12 +2595,11 @@ module ActionView
|
|
|
2585
2595
|
# Add the submit button for the given form. When no value is given, it checks
|
|
2586
2596
|
# if the object is a new resource or not to create the proper label:
|
|
2587
2597
|
#
|
|
2588
|
-
# <%=
|
|
2598
|
+
# <%= form_with model: @article do |f| %>
|
|
2589
2599
|
# <%= f.button %>
|
|
2590
2600
|
# <% end %>
|
|
2591
|
-
#
|
|
2592
|
-
#
|
|
2593
|
-
# button label; otherwise, it uses "Update Post".
|
|
2601
|
+
# In the example above, if <tt>@article</tt> is a new record, it will use "Create Article" as
|
|
2602
|
+
# button label; otherwise, it uses "Update Article".
|
|
2594
2603
|
#
|
|
2595
2604
|
# Those labels can be customized using I18n under the +helpers.submit+ key
|
|
2596
2605
|
# (the same as submit helper) and using <tt>%{model}</tt> for translation interpolation:
|
|
@@ -2606,15 +2615,15 @@ module ActionView
|
|
|
2606
2615
|
# en:
|
|
2607
2616
|
# helpers:
|
|
2608
2617
|
# submit:
|
|
2609
|
-
#
|
|
2618
|
+
# article:
|
|
2610
2619
|
# create: "Add %{model}"
|
|
2611
2620
|
#
|
|
2612
2621
|
# ==== Examples
|
|
2613
|
-
# button("Create
|
|
2614
|
-
# # => <button name='button' type='submit'>Create
|
|
2622
|
+
# button("Create article")
|
|
2623
|
+
# # => <button name='button' type='submit'>Create article</button>
|
|
2615
2624
|
#
|
|
2616
2625
|
# button(:draft, value: true)
|
|
2617
|
-
# # => <button id="
|
|
2626
|
+
# # => <button id="article_draft" name="article[draft]" value="true" type="submit">Create article</button>
|
|
2618
2627
|
#
|
|
2619
2628
|
# button do
|
|
2620
2629
|
# content_tag(:strong, 'Ask me!')
|
|
@@ -2627,13 +2636,13 @@ module ActionView
|
|
|
2627
2636
|
# content_tag(:strong, text)
|
|
2628
2637
|
# end
|
|
2629
2638
|
# # => <button name='button' type='submit'>
|
|
2630
|
-
# # <strong>Create
|
|
2639
|
+
# # <strong>Create article</strong>
|
|
2631
2640
|
# # </button>
|
|
2632
2641
|
#
|
|
2633
2642
|
# button(:draft, value: true) do
|
|
2634
2643
|
# content_tag(:strong, "Save as draft")
|
|
2635
2644
|
# end
|
|
2636
|
-
# # => <button id="
|
|
2645
|
+
# # => <button id="article_draft" name="article[draft]" value="true" type="submit">
|
|
2637
2646
|
# # <strong>Save as draft</strong>
|
|
2638
2647
|
# # </button>
|
|
2639
2648
|
#
|