actionview 4.2.11.1 → 6.0.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +201 -192
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +144 -37
- data/lib/action_view/buffers.rb +18 -1
- data/lib/action_view/cache_expiry.rb +53 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker.rb +54 -20
- data/lib/action_view/digestor.rb +88 -85
- data/lib/action_view/flows.rb +11 -12
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +16 -11
- data/lib/action_view/helpers/asset_tag_helper.rb +241 -82
- data/lib/action_view/helpers/asset_url_helper.rb +171 -67
- data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
- data/lib/action_view/helpers/cache_helper.rb +112 -42
- data/lib/action_view/helpers/capture_helper.rb +20 -13
- data/lib/action_view/helpers/controller_helper.rb +15 -4
- 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 +230 -129
- data/lib/action_view/helpers/debug_helper.rb +7 -6
- data/lib/action_view/helpers/form_helper.rb +755 -129
- data/lib/action_view/helpers/form_options_helper.rb +130 -75
- data/lib/action_view/helpers/form_tag_helper.rb +116 -71
- data/lib/action_view/helpers/javascript_helper.rb +30 -14
- data/lib/action_view/helpers/number_helper.rb +84 -59
- data/lib/action_view/helpers/output_safety_helper.rb +36 -4
- data/lib/action_view/helpers/rendering_helper.rb +11 -8
- data/lib/action_view/helpers/sanitize_helper.rb +30 -31
- data/lib/action_view/helpers/tag_helper.rb +201 -75
- data/lib/action_view/helpers/tags/base.rb +138 -98
- data/lib/action_view/helpers/tags/check_box.rb +20 -19
- 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 +4 -2
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +2 -1
- data/lib/action_view/helpers/tags/date_select.rb +37 -36
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -1
- 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 +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
- data/lib/action_view/helpers/tags/label.rb +3 -2
- data/lib/action_view/helpers/tags/month_field.rb +2 -1
- 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 +2 -1
- 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 +2 -1
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/text_helper.rb +56 -38
- data/lib/action_view/helpers/translation_helper.rb +91 -47
- data/lib/action_view/helpers/url_helper.rb +160 -105
- data/lib/action_view/helpers.rb +5 -3
- data/lib/action_view/layouts.rb +65 -61
- data/lib/action_view/log_subscriber.rb +61 -10
- data/lib/action_view/lookup_context.rb +147 -89
- data/lib/action_view/model_naming.rb +3 -1
- data/lib/action_view/path_set.rb +28 -23
- data/lib/action_view/railtie.rb +62 -6
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/renderer/abstract_renderer.rb +71 -13
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +103 -0
- data/lib/action_view/renderer/partial_renderer.rb +239 -225
- data/lib/action_view/renderer/renderer.rb +22 -8
- data/lib/action_view/renderer/streaming_template_renderer.rb +54 -54
- data/lib/action_view/renderer/template_renderer.rb +79 -73
- data/lib/action_view/rendering.rb +68 -44
- data/lib/action_view/routing_url_for.rb +33 -22
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +44 -29
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +87 -0
- data/lib/action_view/template/handlers/erb.rb +24 -86
- 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 +38 -8
- data/lib/action_view/template/html.rb +19 -10
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +28 -0
- data/lib/action_view/template/resolver.rb +217 -193
- 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 +11 -10
- data/lib/action_view/template/types.rb +18 -18
- data/lib/action_view/template.rb +146 -90
- data/lib/action_view/test_case.rb +52 -32
- data/lib/action_view/testing/resolvers.rb +46 -34
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +48 -31
- data/lib/action_view.rb +11 -8
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +38 -29
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,22 +1,25 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cgi"
|
4
|
+
require "action_view/helpers/date_helper"
|
5
|
+
require "action_view/helpers/tag_helper"
|
6
|
+
require "action_view/helpers/form_tag_helper"
|
7
|
+
require "action_view/helpers/active_model_helper"
|
8
|
+
require "action_view/model_naming"
|
9
|
+
require "action_view/record_identifier"
|
10
|
+
require "active_support/core_ext/module/attribute_accessors"
|
11
|
+
require "active_support/core_ext/hash/slice"
|
12
|
+
require "active_support/core_ext/string/output_safety"
|
13
|
+
require "active_support/core_ext/string/inflections"
|
11
14
|
|
12
15
|
module ActionView
|
13
16
|
# = Action View Form Helpers
|
14
|
-
module Helpers
|
17
|
+
module Helpers #:nodoc:
|
15
18
|
# Form helpers are designed to make working with resources much easier
|
16
19
|
# compared to using vanilla HTML.
|
17
20
|
#
|
18
21
|
# Typically, a form designed to create or update a resource reflects the
|
19
|
-
# identity of the resource in several ways: (i) the
|
22
|
+
# identity of the resource in several ways: (i) the URL that the form is
|
20
23
|
# sent to (the form element's +action+ attribute) should result in a request
|
21
24
|
# being routed to the appropriate controller action (with the appropriate <tt>:id</tt>
|
22
25
|
# parameter in the case of an existing resource), (ii) input fields should
|
@@ -66,9 +69,10 @@ module ActionView
|
|
66
69
|
#
|
67
70
|
# In particular, thanks to the conventions followed in the generated field names, the
|
68
71
|
# controller gets a nested hash <tt>params[:person]</tt> with the person attributes
|
69
|
-
# set in the form. That hash is ready to be passed to <tt>Person.
|
72
|
+
# set in the form. That hash is ready to be passed to <tt>Person.new</tt>:
|
70
73
|
#
|
71
|
-
#
|
74
|
+
# @person = Person.new(params[:person])
|
75
|
+
# if @person.save
|
72
76
|
# # success
|
73
77
|
# else
|
74
78
|
# # error handling
|
@@ -110,6 +114,9 @@ module ActionView
|
|
110
114
|
include FormTagHelper
|
111
115
|
include UrlHelper
|
112
116
|
include ModelNaming
|
117
|
+
include RecordIdentifier
|
118
|
+
|
119
|
+
attr_internal :default_form_builder
|
113
120
|
|
114
121
|
# Creates a form that allows the user to create or update the attributes
|
115
122
|
# of a specific model object.
|
@@ -138,6 +145,7 @@ module ActionView
|
|
138
145
|
# will get expanded to
|
139
146
|
#
|
140
147
|
# <%= text_field :person, :first_name %>
|
148
|
+
#
|
141
149
|
# which results in an HTML <tt><input></tt> tag whose +name+ attribute is
|
142
150
|
# <tt>person[first_name]</tt>. This means that when the form is submitted,
|
143
151
|
# the value entered by the user will be available in the controller as
|
@@ -158,7 +166,7 @@ module ActionView
|
|
158
166
|
# So for example you may use a named route directly. When the model is
|
159
167
|
# represented by a string or symbol, as in the example above, if the
|
160
168
|
# <tt>:url</tt> option is not specified, by default the form will be
|
161
|
-
# sent back to the current
|
169
|
+
# sent back to the current URL (We will describe below an alternative
|
162
170
|
# resource-oriented usage of +form_for+ in which the URL does not need
|
163
171
|
# to be specified explicitly).
|
164
172
|
# * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of
|
@@ -195,9 +203,9 @@ module ActionView
|
|
195
203
|
# <%= f.submit %>
|
196
204
|
# <% end %>
|
197
205
|
#
|
198
|
-
# This also works for the methods in
|
206
|
+
# This also works for the methods in FormOptionsHelper and DateHelper that
|
199
207
|
# are designed to work with an object as base, like
|
200
|
-
#
|
208
|
+
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
|
201
209
|
#
|
202
210
|
# === #form_for with a model object
|
203
211
|
#
|
@@ -410,13 +418,13 @@ module ActionView
|
|
410
418
|
#
|
411
419
|
# To set an authenticity token you need to pass an <tt>:authenticity_token</tt> parameter
|
412
420
|
#
|
413
|
-
# <%= form_for @invoice, url: external_url, authenticity_token: 'external_token' do |f|
|
421
|
+
# <%= form_for @invoice, url: external_url, authenticity_token: 'external_token' do |f| %>
|
414
422
|
# ...
|
415
423
|
# <% end %>
|
416
424
|
#
|
417
425
|
# If you don't want to an authenticity token field be rendered at all just pass <tt>false</tt>:
|
418
426
|
#
|
419
|
-
# <%= form_for @invoice, url: external_url, authenticity_token: false do |f|
|
427
|
+
# <%= form_for @invoice, url: external_url, authenticity_token: false do |f| %>
|
420
428
|
# ...
|
421
429
|
# <% end %>
|
422
430
|
def form_for(record, options = {}, &block)
|
@@ -461,13 +469,300 @@ module ActionView
|
|
461
469
|
)
|
462
470
|
|
463
471
|
options[:url] ||= if options.key?(:format)
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
472
|
+
polymorphic_path(record, format: options.delete(:format))
|
473
|
+
else
|
474
|
+
polymorphic_path(record, {})
|
475
|
+
end
|
468
476
|
end
|
469
477
|
private :apply_form_for_options!
|
470
478
|
|
479
|
+
mattr_accessor :form_with_generates_remote_forms, default: true
|
480
|
+
|
481
|
+
mattr_accessor :form_with_generates_ids, default: false
|
482
|
+
|
483
|
+
# Creates a form tag based on mixing URLs, scopes, or models.
|
484
|
+
#
|
485
|
+
# # Using just a URL:
|
486
|
+
# <%= form_with url: posts_path do |form| %>
|
487
|
+
# <%= form.text_field :title %>
|
488
|
+
# <% end %>
|
489
|
+
# # =>
|
490
|
+
# <form action="/posts" method="post" data-remote="true">
|
491
|
+
# <input type="text" name="title">
|
492
|
+
# </form>
|
493
|
+
#
|
494
|
+
# # Adding a scope prefixes the input field names:
|
495
|
+
# <%= form_with scope: :post, url: posts_path do |form| %>
|
496
|
+
# <%= form.text_field :title %>
|
497
|
+
# <% end %>
|
498
|
+
# # =>
|
499
|
+
# <form action="/posts" method="post" data-remote="true">
|
500
|
+
# <input type="text" name="post[title]">
|
501
|
+
# </form>
|
502
|
+
#
|
503
|
+
# # Using a model infers both the URL and scope:
|
504
|
+
# <%= form_with model: Post.new do |form| %>
|
505
|
+
# <%= form.text_field :title %>
|
506
|
+
# <% end %>
|
507
|
+
# # =>
|
508
|
+
# <form action="/posts" method="post" data-remote="true">
|
509
|
+
# <input type="text" name="post[title]">
|
510
|
+
# </form>
|
511
|
+
#
|
512
|
+
# # An existing model makes an update form and fills out field values:
|
513
|
+
# <%= form_with model: Post.first do |form| %>
|
514
|
+
# <%= form.text_field :title %>
|
515
|
+
# <% end %>
|
516
|
+
# # =>
|
517
|
+
# <form action="/posts/1" method="post" data-remote="true">
|
518
|
+
# <input type="hidden" name="_method" value="patch">
|
519
|
+
# <input type="text" name="post[title]" value="<the title of the post>">
|
520
|
+
# </form>
|
521
|
+
#
|
522
|
+
# # Though the fields don't have to correspond to model attributes:
|
523
|
+
# <%= form_with model: Cat.new do |form| %>
|
524
|
+
# <%= form.text_field :cats_dont_have_gills %>
|
525
|
+
# <%= form.text_field :but_in_forms_they_can %>
|
526
|
+
# <% end %>
|
527
|
+
# # =>
|
528
|
+
# <form action="/cats" method="post" data-remote="true">
|
529
|
+
# <input type="text" name="cat[cats_dont_have_gills]">
|
530
|
+
# <input type="text" name="cat[but_in_forms_they_can]">
|
531
|
+
# </form>
|
532
|
+
#
|
533
|
+
# The parameters in the forms are accessible in controllers according to
|
534
|
+
# their name nesting. So inputs named +title+ and <tt>post[title]</tt> are
|
535
|
+
# accessible as <tt>params[:title]</tt> and <tt>params[:post][:title]</tt>
|
536
|
+
# respectively.
|
537
|
+
#
|
538
|
+
# By default +form_with+ attaches the <tt>data-remote</tt> attribute
|
539
|
+
# submitting the form via an XMLHTTPRequest in the background if an
|
540
|
+
# Unobtrusive JavaScript driver, like rails-ujs, is used. See the
|
541
|
+
# <tt>:local</tt> option for more.
|
542
|
+
#
|
543
|
+
# For ease of comparison the examples above left out the submit button,
|
544
|
+
# as well as the auto generated hidden fields that enable UTF-8 support
|
545
|
+
# and adds an authenticity token needed for cross site request forgery
|
546
|
+
# protection.
|
547
|
+
#
|
548
|
+
# === Resource-oriented style
|
549
|
+
#
|
550
|
+
# In many of the examples just shown, the +:model+ passed to +form_with+
|
551
|
+
# is a _resource_. It corresponds to a set of RESTful routes, most likely
|
552
|
+
# defined via +resources+ in <tt>config/routes.rb</tt>.
|
553
|
+
#
|
554
|
+
# So when passing such a model record, Rails infers the URL and method.
|
555
|
+
#
|
556
|
+
# <%= form_with model: @post do |form| %>
|
557
|
+
# ...
|
558
|
+
# <% end %>
|
559
|
+
#
|
560
|
+
# is then equivalent to something like:
|
561
|
+
#
|
562
|
+
# <%= form_with scope: :post, url: post_path(@post), method: :patch do |form| %>
|
563
|
+
# ...
|
564
|
+
# <% end %>
|
565
|
+
#
|
566
|
+
# And for a new record
|
567
|
+
#
|
568
|
+
# <%= form_with model: Post.new do |form| %>
|
569
|
+
# ...
|
570
|
+
# <% end %>
|
571
|
+
#
|
572
|
+
# is equivalent to something like:
|
573
|
+
#
|
574
|
+
# <%= form_with scope: :post, url: posts_path do |form| %>
|
575
|
+
# ...
|
576
|
+
# <% end %>
|
577
|
+
#
|
578
|
+
# ==== +form_with+ options
|
579
|
+
#
|
580
|
+
# * <tt>:url</tt> - The URL the form submits to. Akin to values passed to
|
581
|
+
# +url_for+ or +link_to+. For example, you may use a named route
|
582
|
+
# directly. When a <tt>:scope</tt> is passed without a <tt>:url</tt> the
|
583
|
+
# form just submits to the current URL.
|
584
|
+
# * <tt>:method</tt> - The method to use when submitting the form, usually
|
585
|
+
# either "get" or "post". If "patch", "put", "delete", or another verb
|
586
|
+
# is used, a hidden input named <tt>_method</tt> is added to
|
587
|
+
# simulate the verb over post.
|
588
|
+
# * <tt>:format</tt> - The format of the route the form submits to.
|
589
|
+
# Useful when submitting to another resource type, like <tt>:json</tt>.
|
590
|
+
# Skipped if a <tt>:url</tt> is passed.
|
591
|
+
# * <tt>:scope</tt> - The scope to prefix input field names with and
|
592
|
+
# thereby how the submitted parameters are grouped in controllers.
|
593
|
+
# * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of
|
594
|
+
# id attributes on form elements. The namespace attribute will be prefixed
|
595
|
+
# with underscore on the generated HTML id.
|
596
|
+
# * <tt>:model</tt> - A model object to infer the <tt>:url</tt> and
|
597
|
+
# <tt>:scope</tt> by, plus fill out input field values.
|
598
|
+
# So if a +title+ attribute is set to "Ahoy!" then a +title+ input
|
599
|
+
# field's value would be "Ahoy!".
|
600
|
+
# If the model is a new record a create form is generated, if an
|
601
|
+
# existing record, however, an update form is generated.
|
602
|
+
# Pass <tt>:scope</tt> or <tt>:url</tt> to override the defaults.
|
603
|
+
# E.g. turn <tt>params[:post]</tt> into <tt>params[:article]</tt>.
|
604
|
+
# * <tt>:authenticity_token</tt> - Authenticity token to use in the form.
|
605
|
+
# Override with a custom authenticity token or pass <tt>false</tt> to
|
606
|
+
# skip the authenticity token field altogether.
|
607
|
+
# Useful when submitting to an external resource like a payment gateway
|
608
|
+
# that might limit the valid fields.
|
609
|
+
# Remote forms may omit the embedded authenticity token by setting
|
610
|
+
# <tt>config.action_view.embed_authenticity_token_in_remote_forms = false</tt>.
|
611
|
+
# This is helpful when fragment-caching the form. Remote forms
|
612
|
+
# get the authenticity token from the <tt>meta</tt> tag, so embedding is
|
613
|
+
# unnecessary unless you support browsers without JavaScript.
|
614
|
+
# * <tt>:local</tt> - By default form submits are remote and unobtrusive XHRs.
|
615
|
+
# Disable remote submits with <tt>local: true</tt>.
|
616
|
+
# * <tt>:skip_enforcing_utf8</tt> - If set to true, a hidden input with name
|
617
|
+
# utf8 is not output.
|
618
|
+
# * <tt>:builder</tt> - Override the object used to build the form.
|
619
|
+
# * <tt>:id</tt> - Optional HTML id attribute.
|
620
|
+
# * <tt>:class</tt> - Optional HTML class attribute.
|
621
|
+
# * <tt>:data</tt> - Optional HTML data attributes.
|
622
|
+
# * <tt>:html</tt> - Other optional HTML attributes for the form tag.
|
623
|
+
#
|
624
|
+
# === Examples
|
625
|
+
#
|
626
|
+
# When not passing a block, +form_with+ just generates an opening form tag.
|
627
|
+
#
|
628
|
+
# <%= form_with(model: @post, url: super_posts_path) %>
|
629
|
+
# <%= form_with(model: @post, scope: :article) %>
|
630
|
+
# <%= form_with(model: @post, format: :json) %>
|
631
|
+
# <%= form_with(model: @post, authenticity_token: false) %> # Disables the token.
|
632
|
+
#
|
633
|
+
# For namespaced routes, like +admin_post_url+:
|
634
|
+
#
|
635
|
+
# <%= form_with(model: [ :admin, @post ]) do |form| %>
|
636
|
+
# ...
|
637
|
+
# <% end %>
|
638
|
+
#
|
639
|
+
# If your resource has associations defined, for example, you want to add comments
|
640
|
+
# to the document given that the routes are set correctly:
|
641
|
+
#
|
642
|
+
# <%= form_with(model: [ @document, Comment.new ]) do |form| %>
|
643
|
+
# ...
|
644
|
+
# <% end %>
|
645
|
+
#
|
646
|
+
# Where <tt>@document = Document.find(params[:id])</tt>.
|
647
|
+
#
|
648
|
+
# === Mixing with other form helpers
|
649
|
+
#
|
650
|
+
# While +form_with+ uses a FormBuilder object it's possible to mix and
|
651
|
+
# match the stand-alone FormHelper methods and methods
|
652
|
+
# from FormTagHelper:
|
653
|
+
#
|
654
|
+
# <%= form_with scope: :person do |form| %>
|
655
|
+
# <%= form.text_field :first_name %>
|
656
|
+
# <%= form.text_field :last_name %>
|
657
|
+
#
|
658
|
+
# <%= text_area :person, :biography %>
|
659
|
+
# <%= check_box_tag "person[admin]", "1", @person.company.admin? %>
|
660
|
+
#
|
661
|
+
# <%= form.submit %>
|
662
|
+
# <% end %>
|
663
|
+
#
|
664
|
+
# Same goes for the methods in FormOptionsHelper and DateHelper designed
|
665
|
+
# to work with an object as a base, like
|
666
|
+
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
|
667
|
+
#
|
668
|
+
# === Setting the method
|
669
|
+
#
|
670
|
+
# You can force the form to use the full array of HTTP verbs by setting
|
671
|
+
#
|
672
|
+
# method: (:get|:post|:patch|:put|:delete)
|
673
|
+
#
|
674
|
+
# in the options hash. If the verb is not GET or POST, which are natively
|
675
|
+
# supported by HTML forms, the form will be set to POST and a hidden input
|
676
|
+
# called _method will carry the intended verb for the server to interpret.
|
677
|
+
#
|
678
|
+
# === Setting HTML options
|
679
|
+
#
|
680
|
+
# You can set data attributes directly in a data hash, but HTML options
|
681
|
+
# besides id and class must be wrapped in an HTML key:
|
682
|
+
#
|
683
|
+
# <%= form_with(model: @post, data: { behavior: "autosave" }, html: { name: "go" }) do |form| %>
|
684
|
+
# ...
|
685
|
+
# <% end %>
|
686
|
+
#
|
687
|
+
# generates
|
688
|
+
#
|
689
|
+
# <form action="/posts/123" method="post" data-behavior="autosave" name="go">
|
690
|
+
# <input name="_method" type="hidden" value="patch" />
|
691
|
+
# ...
|
692
|
+
# </form>
|
693
|
+
#
|
694
|
+
# === Removing hidden model id's
|
695
|
+
#
|
696
|
+
# The +form_with+ method automatically includes the model id as a hidden field in the form.
|
697
|
+
# This is used to maintain the correlation between the form data and its associated model.
|
698
|
+
# Some ORM systems do not use IDs on nested models so in this case you want to be able
|
699
|
+
# to disable the hidden id.
|
700
|
+
#
|
701
|
+
# In the following example the Post model has many Comments stored within it in a NoSQL database,
|
702
|
+
# thus there is no primary key for comments.
|
703
|
+
#
|
704
|
+
# <%= form_with(model: @post) do |form| %>
|
705
|
+
# <%= form.fields(:comments, skip_id: true) do |fields| %>
|
706
|
+
# ...
|
707
|
+
# <% end %>
|
708
|
+
# <% end %>
|
709
|
+
#
|
710
|
+
# === Customized form builders
|
711
|
+
#
|
712
|
+
# You can also build forms using a customized FormBuilder class. Subclass
|
713
|
+
# FormBuilder and override or define some more helpers, then use your
|
714
|
+
# custom builder. For example, let's say you made a helper to
|
715
|
+
# automatically add labels to form inputs.
|
716
|
+
#
|
717
|
+
# <%= form_with model: @person, url: { action: "create" }, builder: LabellingFormBuilder do |form| %>
|
718
|
+
# <%= form.text_field :first_name %>
|
719
|
+
# <%= form.text_field :last_name %>
|
720
|
+
# <%= form.text_area :biography %>
|
721
|
+
# <%= form.check_box :admin %>
|
722
|
+
# <%= form.submit %>
|
723
|
+
# <% end %>
|
724
|
+
#
|
725
|
+
# In this case, if you use:
|
726
|
+
#
|
727
|
+
# <%= render form %>
|
728
|
+
#
|
729
|
+
# The rendered template is <tt>people/_labelling_form</tt> and the local
|
730
|
+
# variable referencing the form builder is called
|
731
|
+
# <tt>labelling_form</tt>.
|
732
|
+
#
|
733
|
+
# The custom FormBuilder class is automatically merged with the options
|
734
|
+
# of a nested +fields+ call, unless it's explicitly set.
|
735
|
+
#
|
736
|
+
# In many cases you will want to wrap the above in another helper, so you
|
737
|
+
# could do something like the following:
|
738
|
+
#
|
739
|
+
# def labelled_form_with(**options, &block)
|
740
|
+
# form_with(**options.merge(builder: LabellingFormBuilder), &block)
|
741
|
+
# end
|
742
|
+
def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
|
743
|
+
options[:allow_method_names_outside_object] = true
|
744
|
+
options[:skip_default_ids] = !form_with_generates_ids
|
745
|
+
|
746
|
+
if model
|
747
|
+
url ||= polymorphic_path(model, format: format)
|
748
|
+
|
749
|
+
model = model.last if model.is_a?(Array)
|
750
|
+
scope ||= model_name_from_record_or_class(model).param_key
|
751
|
+
end
|
752
|
+
|
753
|
+
if block_given?
|
754
|
+
builder = instantiate_builder(scope, model, options)
|
755
|
+
output = capture(builder, &block)
|
756
|
+
options[:multipart] ||= builder.multipart?
|
757
|
+
|
758
|
+
html_options = html_options_for_form_with(url, model, **options)
|
759
|
+
form_tag_with_body(html_options, output)
|
760
|
+
else
|
761
|
+
html_options = html_options_for_form_with(url, model, **options)
|
762
|
+
form_tag_html(html_options)
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
471
766
|
# Creates a scope around a specific model object like form_for, but
|
472
767
|
# doesn't create the form tags themselves. This makes fields_for suitable
|
473
768
|
# for specifying additional model objects in the same form.
|
@@ -525,9 +820,9 @@ module ActionView
|
|
525
820
|
# _class_ of the model object, e.g. if <tt>@person.permission</tt>, is
|
526
821
|
# of class +Permission+, the field will still be named <tt>permission[admin]</tt>.
|
527
822
|
#
|
528
|
-
# Note: This also works for the methods in
|
823
|
+
# Note: This also works for the methods in FormOptionsHelper and
|
529
824
|
# DateHelper that are designed to work with an object as base, like
|
530
|
-
#
|
825
|
+
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
|
531
826
|
#
|
532
827
|
# === Nested Attributes Examples
|
533
828
|
#
|
@@ -714,6 +1009,63 @@ module ActionView
|
|
714
1009
|
capture(builder, &block)
|
715
1010
|
end
|
716
1011
|
|
1012
|
+
# Scopes input fields with either an explicit scope or model.
|
1013
|
+
# Like +form_with+ does with <tt>:scope</tt> or <tt>:model</tt>,
|
1014
|
+
# except it doesn't output the form tags.
|
1015
|
+
#
|
1016
|
+
# # Using a scope prefixes the input field names:
|
1017
|
+
# <%= fields :comment do |fields| %>
|
1018
|
+
# <%= fields.text_field :body %>
|
1019
|
+
# <% end %>
|
1020
|
+
# # => <input type="text" name="comment[body]">
|
1021
|
+
#
|
1022
|
+
# # Using a model infers the scope and assigns field values:
|
1023
|
+
# <%= fields model: Comment.new(body: "full bodied") do |fields| %>
|
1024
|
+
# <%= fields.text_field :body %>
|
1025
|
+
# <% end %>
|
1026
|
+
# # => <input type="text" name="comment[body]" value="full bodied">
|
1027
|
+
#
|
1028
|
+
# # Using +fields+ with +form_with+:
|
1029
|
+
# <%= form_with model: @post do |form| %>
|
1030
|
+
# <%= form.text_field :title %>
|
1031
|
+
#
|
1032
|
+
# <%= form.fields :comment do |fields| %>
|
1033
|
+
# <%= fields.text_field :body %>
|
1034
|
+
# <% end %>
|
1035
|
+
# <% end %>
|
1036
|
+
#
|
1037
|
+
# Much like +form_with+ a FormBuilder instance associated with the scope
|
1038
|
+
# or model is yielded, so any generated field names are prefixed with
|
1039
|
+
# either the passed scope or the scope inferred from the <tt>:model</tt>.
|
1040
|
+
#
|
1041
|
+
# === Mixing with other form helpers
|
1042
|
+
#
|
1043
|
+
# While +form_with+ uses a FormBuilder object it's possible to mix and
|
1044
|
+
# match the stand-alone FormHelper methods and methods
|
1045
|
+
# from FormTagHelper:
|
1046
|
+
#
|
1047
|
+
# <%= fields model: @comment do |fields| %>
|
1048
|
+
# <%= fields.text_field :body %>
|
1049
|
+
#
|
1050
|
+
# <%= text_area :commenter, :biography %>
|
1051
|
+
# <%= check_box_tag "comment[all_caps]", "1", @comment.commenter.hulk_mode? %>
|
1052
|
+
# <% end %>
|
1053
|
+
#
|
1054
|
+
# Same goes for the methods in FormOptionsHelper and DateHelper designed
|
1055
|
+
# to work with an object as a base, like
|
1056
|
+
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
|
1057
|
+
def fields(scope = nil, model: nil, **options, &block)
|
1058
|
+
options[:allow_method_names_outside_object] = true
|
1059
|
+
options[:skip_default_ids] = !form_with_generates_ids
|
1060
|
+
|
1061
|
+
if model
|
1062
|
+
scope ||= model_name_from_record_or_class(model).param_key
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
builder = instantiate_builder(scope, model, options)
|
1066
|
+
capture(builder, &block)
|
1067
|
+
end
|
1068
|
+
|
717
1069
|
# Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
|
718
1070
|
# assigned to the template (identified by +object+). The text of label will default to the attribute name unless a translation
|
719
1071
|
# is found in the current I18n locale (through helpers.label.<modelname>.<attribute>) or you specify it explicitly.
|
@@ -759,7 +1111,7 @@ module ActionView
|
|
759
1111
|
# # => <label for="post_privacy_public">Public Post</label>
|
760
1112
|
#
|
761
1113
|
# label(:post, :terms) do
|
762
|
-
# 'Accept <a href="/terms">Terms</a>.'
|
1114
|
+
# raw('Accept <a href="/terms">Terms</a>.')
|
763
1115
|
# end
|
764
1116
|
# # => <label for="post_terms">Accept <a href="/terms">Terms</a>.</label>
|
765
1117
|
def label(object_name, method, content_or_options = nil, options = nil, &block)
|
@@ -778,6 +1130,9 @@ module ActionView
|
|
778
1130
|
# text_field(:post, :title, class: "create_input")
|
779
1131
|
# # => <input type="text" id="post_title" name="post[title]" value="#{@post.title}" class="create_input" />
|
780
1132
|
#
|
1133
|
+
# text_field(:post, :title, maxlength: 30, class: "title_input")
|
1134
|
+
# # => <input type="text" id="post_title" name="post[title]" maxlength="30" size="30" value="#{@post.title}" class="title_input" />
|
1135
|
+
#
|
781
1136
|
# text_field(:session, :user, onchange: "if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }")
|
782
1137
|
# # => <input type="text" id="session_user" name="session[user]" value="#{@session.user}" onchange="if ($('#session_user').val() === 'admin') { alert('Your login cannot be admin!'); }"/>
|
783
1138
|
#
|
@@ -843,8 +1198,8 @@ module ActionView
|
|
843
1198
|
# file_field(:user, :avatar)
|
844
1199
|
# # => <input type="file" id="user_avatar" name="user[avatar]" />
|
845
1200
|
#
|
846
|
-
# file_field(:post, :image, :
|
847
|
-
# # => <input type="file" id="post_image" name="post[image]" multiple="
|
1201
|
+
# file_field(:post, :image, multiple: true)
|
1202
|
+
# # => <input type="file" id="post_image" name="post[image][]" multiple="multiple" />
|
848
1203
|
#
|
849
1204
|
# file_field(:post, :attached, accept: 'text/html')
|
850
1205
|
# # => <input accept="text/html" type="file" id="post_attached" name="post[attached]" />
|
@@ -855,7 +1210,7 @@ module ActionView
|
|
855
1210
|
# file_field(:attachment, :file, class: 'file_input')
|
856
1211
|
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
|
857
1212
|
def file_field(object_name, method, options = {})
|
858
|
-
Tags::FileField.new(object_name, method, self, options).render
|
1213
|
+
Tags::FileField.new(object_name, method, self, convert_direct_upload_option_to_url(options.dup)).render
|
859
1214
|
end
|
860
1215
|
|
861
1216
|
# Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +method+)
|
@@ -959,6 +1314,7 @@ module ActionView
|
|
959
1314
|
# # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" />
|
960
1315
|
# # <input type="radio" id="post_category_java" name="post[category]" value="java" />
|
961
1316
|
#
|
1317
|
+
# # Let's say that @user.receive_newsletter returns "no":
|
962
1318
|
# radio_button("user", "receive_newsletter", "yes")
|
963
1319
|
# radio_button("user", "receive_newsletter", "no")
|
964
1320
|
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
|
@@ -1014,7 +1370,7 @@ module ActionView
|
|
1014
1370
|
# date_field("user", "born_on")
|
1015
1371
|
# # => <input id="user_born_on" name="user[born_on]" type="date" />
|
1016
1372
|
#
|
1017
|
-
# The default value is generated by trying to call "
|
1373
|
+
# The default value is generated by trying to call +strftime+ with "%Y-%m-%d"
|
1018
1374
|
# on the object's value, which makes it behave as expected for instances
|
1019
1375
|
# of DateTime and ActiveSupport::TimeWithZone. You can still override that
|
1020
1376
|
# by passing the "value" option explicitly, e.g.
|
@@ -1042,7 +1398,7 @@ module ActionView
|
|
1042
1398
|
# Returns a text_field of type "time".
|
1043
1399
|
#
|
1044
1400
|
# The default value is generated by trying to call +strftime+ with "%T.%L"
|
1045
|
-
# on the
|
1401
|
+
# on the object's value. It is still possible to override that
|
1046
1402
|
# by passing the "value" option.
|
1047
1403
|
#
|
1048
1404
|
# === Options
|
@@ -1068,38 +1424,9 @@ module ActionView
|
|
1068
1424
|
Tags::TimeField.new(object_name, method, self, options).render
|
1069
1425
|
end
|
1070
1426
|
|
1071
|
-
# Returns a text_field of type "datetime".
|
1072
|
-
#
|
1073
|
-
# datetime_field("user", "born_on")
|
1074
|
-
# # => <input id="user_born_on" name="user[born_on]" type="datetime" />
|
1075
|
-
#
|
1076
|
-
# The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T.%L%z"
|
1077
|
-
# on the object's value, which makes it behave as expected for instances
|
1078
|
-
# of DateTime and ActiveSupport::TimeWithZone.
|
1079
|
-
#
|
1080
|
-
# @user.born_on = Date.new(1984, 1, 12)
|
1081
|
-
# datetime_field("user", "born_on")
|
1082
|
-
# # => <input id="user_born_on" name="user[born_on]" type="datetime" value="1984-01-12T00:00:00.000+0000" />
|
1083
|
-
#
|
1084
|
-
# You can create values for the "min" and "max" attributes by passing
|
1085
|
-
# instances of Date or Time to the options hash.
|
1086
|
-
#
|
1087
|
-
# datetime_field("user", "born_on", min: Date.today)
|
1088
|
-
# # => <input id="user_born_on" name="user[born_on]" type="datetime" min="2014-05-20T00:00:00.000+0000" />
|
1089
|
-
#
|
1090
|
-
# Alternatively, you can pass a String formatted as an ISO8601 datetime
|
1091
|
-
# with UTC offset as the values for "min" and "max."
|
1092
|
-
#
|
1093
|
-
# datetime_field("user", "born_on", min: "2014-05-20T00:00:00+0000")
|
1094
|
-
# # => <input id="user_born_on" name="user[born_on]" type="datetime" min="2014-05-20T00:00:00.000+0000" />
|
1095
|
-
#
|
1096
|
-
def datetime_field(object_name, method, options = {})
|
1097
|
-
Tags::DatetimeField.new(object_name, method, self, options).render
|
1098
|
-
end
|
1099
|
-
|
1100
1427
|
# Returns a text_field of type "datetime-local".
|
1101
1428
|
#
|
1102
|
-
#
|
1429
|
+
# datetime_field("user", "born_on")
|
1103
1430
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" />
|
1104
1431
|
#
|
1105
1432
|
# The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T"
|
@@ -1107,25 +1434,27 @@ module ActionView
|
|
1107
1434
|
# of DateTime and ActiveSupport::TimeWithZone.
|
1108
1435
|
#
|
1109
1436
|
# @user.born_on = Date.new(1984, 1, 12)
|
1110
|
-
#
|
1437
|
+
# datetime_field("user", "born_on")
|
1111
1438
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" value="1984-01-12T00:00:00" />
|
1112
1439
|
#
|
1113
1440
|
# You can create values for the "min" and "max" attributes by passing
|
1114
1441
|
# instances of Date or Time to the options hash.
|
1115
1442
|
#
|
1116
|
-
#
|
1443
|
+
# datetime_field("user", "born_on", min: Date.today)
|
1117
1444
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" min="2014-05-20T00:00:00.000" />
|
1118
1445
|
#
|
1119
1446
|
# Alternatively, you can pass a String formatted as an ISO8601 datetime as
|
1120
1447
|
# the values for "min" and "max."
|
1121
1448
|
#
|
1122
|
-
#
|
1449
|
+
# datetime_field("user", "born_on", min: "2014-05-20T00:00:00")
|
1123
1450
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" min="2014-05-20T00:00:00.000" />
|
1124
1451
|
#
|
1125
|
-
def
|
1452
|
+
def datetime_field(object_name, method, options = {})
|
1126
1453
|
Tags::DatetimeLocalField.new(object_name, method, self, options).render
|
1127
1454
|
end
|
1128
1455
|
|
1456
|
+
alias datetime_local_field datetime_field
|
1457
|
+
|
1129
1458
|
# Returns a text_field of type "month".
|
1130
1459
|
#
|
1131
1460
|
# month_field("user", "born_on")
|
@@ -1195,6 +1524,34 @@ module ActionView
|
|
1195
1524
|
end
|
1196
1525
|
|
1197
1526
|
private
|
1527
|
+
def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: !form_with_generates_remote_forms,
|
1528
|
+
skip_enforcing_utf8: nil, **options)
|
1529
|
+
html_options = options.slice(:id, :class, :multipart, :method, :data).merge(html)
|
1530
|
+
html_options[:method] ||= :patch if model.respond_to?(:persisted?) && model.persisted?
|
1531
|
+
html_options[:enforce_utf8] = !skip_enforcing_utf8 unless skip_enforcing_utf8.nil?
|
1532
|
+
|
1533
|
+
html_options[:enctype] = "multipart/form-data" if html_options.delete(:multipart)
|
1534
|
+
|
1535
|
+
# The following URL is unescaped, this is just a hash of options, and it is the
|
1536
|
+
# responsibility of the caller to escape all the values.
|
1537
|
+
html_options[:action] = url_for(url_for_options || {})
|
1538
|
+
html_options[:"accept-charset"] = "UTF-8"
|
1539
|
+
html_options[:"data-remote"] = true unless local
|
1540
|
+
|
1541
|
+
html_options[:authenticity_token] = options.delete(:authenticity_token)
|
1542
|
+
|
1543
|
+
if !local && html_options[:authenticity_token].blank?
|
1544
|
+
html_options[:authenticity_token] = embed_authenticity_token_in_remote_forms
|
1545
|
+
end
|
1546
|
+
|
1547
|
+
if html_options[:authenticity_token] == true
|
1548
|
+
# Include the default authenticity_token, which is only generated when it's set to nil,
|
1549
|
+
# but we needed the true value to override the default of no authenticity_token on data-remote.
|
1550
|
+
html_options[:authenticity_token] = nil
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
html_options.stringify_keys!
|
1554
|
+
end
|
1198
1555
|
|
1199
1556
|
def instantiate_builder(record_name, record_object, options)
|
1200
1557
|
case record_name
|
@@ -1203,7 +1560,7 @@ module ActionView
|
|
1203
1560
|
object_name = record_name
|
1204
1561
|
else
|
1205
1562
|
object = record_name
|
1206
|
-
object_name = model_name_from_record_or_class(object).param_key
|
1563
|
+
object_name = model_name_from_record_or_class(object).param_key if object
|
1207
1564
|
end
|
1208
1565
|
|
1209
1566
|
builder = options[:builder] || default_form_builder_class
|
@@ -1211,7 +1568,7 @@ module ActionView
|
|
1211
1568
|
end
|
1212
1569
|
|
1213
1570
|
def default_form_builder_class
|
1214
|
-
builder = ActionView::Base.default_form_builder
|
1571
|
+
builder = default_form_builder || ActionView::Base.default_form_builder
|
1215
1572
|
builder.respond_to?(:constantize) ? builder.constantize : builder
|
1216
1573
|
end
|
1217
1574
|
end
|
@@ -1229,7 +1586,7 @@ module ActionView
|
|
1229
1586
|
# In the above block, a +FormBuilder+ object is yielded as the
|
1230
1587
|
# +person_form+ variable. This allows you to generate the +text_field+
|
1231
1588
|
# and +check_box+ fields by specifying their eponymous methods, which
|
1232
|
-
# modify the underlying template and associates the
|
1589
|
+
# modify the underlying template and associates the <tt>@person</tt> model object
|
1233
1590
|
# with the form.
|
1234
1591
|
#
|
1235
1592
|
# The +FormBuilder+ object can be thought of as serving as a proxy for the
|
@@ -1268,14 +1625,15 @@ module ActionView
|
|
1268
1625
|
include ModelNaming
|
1269
1626
|
|
1270
1627
|
# The methods which wrap a form helper call.
|
1271
|
-
class_attribute :field_helpers
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1628
|
+
class_attribute :field_helpers, default: [
|
1629
|
+
:fields_for, :fields, :label, :text_field, :password_field,
|
1630
|
+
:hidden_field, :file_field, :text_area, :check_box,
|
1631
|
+
:radio_button, :color_field, :search_field,
|
1632
|
+
:telephone_field, :phone_field, :date_field,
|
1633
|
+
:time_field, :datetime_field, :datetime_local_field,
|
1634
|
+
:month_field, :week_field, :url_field, :email_field,
|
1635
|
+
:number_field, :range_field
|
1636
|
+
]
|
1279
1637
|
|
1280
1638
|
attr_accessor :object_name, :object, :options
|
1281
1639
|
|
@@ -1291,7 +1649,7 @@ module ActionView
|
|
1291
1649
|
end
|
1292
1650
|
|
1293
1651
|
def self._to_partial_path
|
1294
|
-
@_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/,
|
1652
|
+
@_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/, "")
|
1295
1653
|
end
|
1296
1654
|
|
1297
1655
|
def to_partial_path
|
@@ -1305,19 +1663,245 @@ module ActionView
|
|
1305
1663
|
def initialize(object_name, object, template, options)
|
1306
1664
|
@nested_child_index = {}
|
1307
1665
|
@object_name, @object, @template, @options = object_name, object, template, options
|
1308
|
-
@default_options = @options ? @options.slice(:index, :namespace) : {}
|
1666
|
+
@default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids, :allow_method_names_outside_object) : {}
|
1667
|
+
@default_html_options = @default_options.except(:skip_default_ids, :allow_method_names_outside_object)
|
1668
|
+
|
1669
|
+
convert_to_legacy_options(@options)
|
1670
|
+
|
1309
1671
|
if @object_name.to_s.match(/\[\]$/)
|
1310
|
-
if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")
|
1672
|
+
if (object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")) && object.respond_to?(:to_param)
|
1311
1673
|
@auto_index = object.to_param
|
1312
1674
|
else
|
1313
1675
|
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
|
1314
1676
|
end
|
1315
1677
|
end
|
1678
|
+
|
1316
1679
|
@multipart = nil
|
1317
1680
|
@index = options[:index] || options[:child_index]
|
1318
1681
|
end
|
1319
1682
|
|
1320
|
-
|
1683
|
+
##
|
1684
|
+
# :method: text_field
|
1685
|
+
#
|
1686
|
+
# :call-seq: text_field(method, options = {})
|
1687
|
+
#
|
1688
|
+
# Wraps ActionView::Helpers::FormHelper#text_field for form builders:
|
1689
|
+
#
|
1690
|
+
# <%= form_with model: @user do |f| %>
|
1691
|
+
# <%= f.text_field :name %>
|
1692
|
+
# <% end %>
|
1693
|
+
#
|
1694
|
+
# Please refer to the documentation of the base helper for details.
|
1695
|
+
|
1696
|
+
##
|
1697
|
+
# :method: password_field
|
1698
|
+
#
|
1699
|
+
# :call-seq: password_field(method, options = {})
|
1700
|
+
#
|
1701
|
+
# Wraps ActionView::Helpers::FormHelper#password_field for form builders:
|
1702
|
+
#
|
1703
|
+
# <%= form_with model: @user do |f| %>
|
1704
|
+
# <%= f.password_field :password %>
|
1705
|
+
# <% end %>
|
1706
|
+
#
|
1707
|
+
# Please refer to the documentation of the base helper for details.
|
1708
|
+
|
1709
|
+
##
|
1710
|
+
# :method: text_area
|
1711
|
+
#
|
1712
|
+
# :call-seq: text_area(method, options = {})
|
1713
|
+
#
|
1714
|
+
# Wraps ActionView::Helpers::FormHelper#text_area for form builders:
|
1715
|
+
#
|
1716
|
+
# <%= form_with model: @user do |f| %>
|
1717
|
+
# <%= f.text_area :detail %>
|
1718
|
+
# <% end %>
|
1719
|
+
#
|
1720
|
+
# Please refer to the documentation of the base helper for details.
|
1721
|
+
|
1722
|
+
##
|
1723
|
+
# :method: color_field
|
1724
|
+
#
|
1725
|
+
# :call-seq: color_field(method, options = {})
|
1726
|
+
#
|
1727
|
+
# Wraps ActionView::Helpers::FormHelper#color_field for form builders:
|
1728
|
+
#
|
1729
|
+
# <%= form_with model: @user do |f| %>
|
1730
|
+
# <%= f.color_field :favorite_color %>
|
1731
|
+
# <% end %>
|
1732
|
+
#
|
1733
|
+
# Please refer to the documentation of the base helper for details.
|
1734
|
+
|
1735
|
+
##
|
1736
|
+
# :method: search_field
|
1737
|
+
#
|
1738
|
+
# :call-seq: search_field(method, options = {})
|
1739
|
+
#
|
1740
|
+
# Wraps ActionView::Helpers::FormHelper#search_field for form builders:
|
1741
|
+
#
|
1742
|
+
# <%= form_with model: @user do |f| %>
|
1743
|
+
# <%= f.search_field :name %>
|
1744
|
+
# <% end %>
|
1745
|
+
#
|
1746
|
+
# Please refer to the documentation of the base helper for details.
|
1747
|
+
|
1748
|
+
##
|
1749
|
+
# :method: telephone_field
|
1750
|
+
#
|
1751
|
+
# :call-seq: telephone_field(method, options = {})
|
1752
|
+
#
|
1753
|
+
# Wraps ActionView::Helpers::FormHelper#telephone_field for form builders:
|
1754
|
+
#
|
1755
|
+
# <%= form_with model: @user do |f| %>
|
1756
|
+
# <%= f.telephone_field :phone %>
|
1757
|
+
# <% end %>
|
1758
|
+
#
|
1759
|
+
# Please refer to the documentation of the base helper for details.
|
1760
|
+
|
1761
|
+
##
|
1762
|
+
# :method: phone_field
|
1763
|
+
#
|
1764
|
+
# :call-seq: phone_field(method, options = {})
|
1765
|
+
#
|
1766
|
+
# Wraps ActionView::Helpers::FormHelper#phone_field for form builders:
|
1767
|
+
#
|
1768
|
+
# <%= form_with model: @user do |f| %>
|
1769
|
+
# <%= f.phone_field :phone %>
|
1770
|
+
# <% end %>
|
1771
|
+
#
|
1772
|
+
# Please refer to the documentation of the base helper for details.
|
1773
|
+
|
1774
|
+
##
|
1775
|
+
# :method: date_field
|
1776
|
+
#
|
1777
|
+
# :call-seq: date_field(method, options = {})
|
1778
|
+
#
|
1779
|
+
# Wraps ActionView::Helpers::FormHelper#date_field for form builders:
|
1780
|
+
#
|
1781
|
+
# <%= form_with model: @user do |f| %>
|
1782
|
+
# <%= f.date_field :born_on %>
|
1783
|
+
# <% end %>
|
1784
|
+
#
|
1785
|
+
# Please refer to the documentation of the base helper for details.
|
1786
|
+
|
1787
|
+
##
|
1788
|
+
# :method: time_field
|
1789
|
+
#
|
1790
|
+
# :call-seq: time_field(method, options = {})
|
1791
|
+
#
|
1792
|
+
# Wraps ActionView::Helpers::FormHelper#time_field for form builders:
|
1793
|
+
#
|
1794
|
+
# <%= form_with model: @user do |f| %>
|
1795
|
+
# <%= f.time_field :borned_at %>
|
1796
|
+
# <% end %>
|
1797
|
+
#
|
1798
|
+
# Please refer to the documentation of the base helper for details.
|
1799
|
+
|
1800
|
+
##
|
1801
|
+
# :method: datetime_field
|
1802
|
+
#
|
1803
|
+
# :call-seq: datetime_field(method, options = {})
|
1804
|
+
#
|
1805
|
+
# Wraps ActionView::Helpers::FormHelper#datetime_field for form builders:
|
1806
|
+
#
|
1807
|
+
# <%= form_with model: @user do |f| %>
|
1808
|
+
# <%= f.datetime_field :graduation_day %>
|
1809
|
+
# <% end %>
|
1810
|
+
#
|
1811
|
+
# Please refer to the documentation of the base helper for details.
|
1812
|
+
|
1813
|
+
##
|
1814
|
+
# :method: datetime_local_field
|
1815
|
+
#
|
1816
|
+
# :call-seq: datetime_local_field(method, options = {})
|
1817
|
+
#
|
1818
|
+
# Wraps ActionView::Helpers::FormHelper#datetime_local_field for form builders:
|
1819
|
+
#
|
1820
|
+
# <%= form_with model: @user do |f| %>
|
1821
|
+
# <%= f.datetime_local_field :graduation_day %>
|
1822
|
+
# <% end %>
|
1823
|
+
#
|
1824
|
+
# Please refer to the documentation of the base helper for details.
|
1825
|
+
|
1826
|
+
##
|
1827
|
+
# :method: month_field
|
1828
|
+
#
|
1829
|
+
# :call-seq: month_field(method, options = {})
|
1830
|
+
#
|
1831
|
+
# Wraps ActionView::Helpers::FormHelper#month_field for form builders:
|
1832
|
+
#
|
1833
|
+
# <%= form_with model: @user do |f| %>
|
1834
|
+
# <%= f.month_field :birthday_month %>
|
1835
|
+
# <% end %>
|
1836
|
+
#
|
1837
|
+
# Please refer to the documentation of the base helper for details.
|
1838
|
+
|
1839
|
+
##
|
1840
|
+
# :method: week_field
|
1841
|
+
#
|
1842
|
+
# :call-seq: week_field(method, options = {})
|
1843
|
+
#
|
1844
|
+
# Wraps ActionView::Helpers::FormHelper#week_field for form builders:
|
1845
|
+
#
|
1846
|
+
# <%= form_with model: @user do |f| %>
|
1847
|
+
# <%= f.week_field :birthday_week %>
|
1848
|
+
# <% end %>
|
1849
|
+
#
|
1850
|
+
# Please refer to the documentation of the base helper for details.
|
1851
|
+
|
1852
|
+
##
|
1853
|
+
# :method: url_field
|
1854
|
+
#
|
1855
|
+
# :call-seq: url_field(method, options = {})
|
1856
|
+
#
|
1857
|
+
# Wraps ActionView::Helpers::FormHelper#url_field for form builders:
|
1858
|
+
#
|
1859
|
+
# <%= form_with model: @user do |f| %>
|
1860
|
+
# <%= f.url_field :homepage %>
|
1861
|
+
# <% end %>
|
1862
|
+
#
|
1863
|
+
# Please refer to the documentation of the base helper for details.
|
1864
|
+
|
1865
|
+
##
|
1866
|
+
# :method: email_field
|
1867
|
+
#
|
1868
|
+
# :call-seq: email_field(method, options = {})
|
1869
|
+
#
|
1870
|
+
# Wraps ActionView::Helpers::FormHelper#email_field for form builders:
|
1871
|
+
#
|
1872
|
+
# <%= form_with model: @user do |f| %>
|
1873
|
+
# <%= f.email_field :address %>
|
1874
|
+
# <% end %>
|
1875
|
+
#
|
1876
|
+
# Please refer to the documentation of the base helper for details.
|
1877
|
+
|
1878
|
+
##
|
1879
|
+
# :method: number_field
|
1880
|
+
#
|
1881
|
+
# :call-seq: number_field(method, options = {})
|
1882
|
+
#
|
1883
|
+
# Wraps ActionView::Helpers::FormHelper#number_field for form builders:
|
1884
|
+
#
|
1885
|
+
# <%= form_with model: @user do |f| %>
|
1886
|
+
# <%= f.number_field :age %>
|
1887
|
+
# <% end %>
|
1888
|
+
#
|
1889
|
+
# Please refer to the documentation of the base helper for details.
|
1890
|
+
|
1891
|
+
##
|
1892
|
+
# :method: range_field
|
1893
|
+
#
|
1894
|
+
# :call-seq: range_field(method, options = {})
|
1895
|
+
#
|
1896
|
+
# Wraps ActionView::Helpers::FormHelper#range_field for form builders:
|
1897
|
+
#
|
1898
|
+
# <%= form_with model: @user do |f| %>
|
1899
|
+
# <%= f.range_field :age %>
|
1900
|
+
# <% end %>
|
1901
|
+
#
|
1902
|
+
# Please refer to the documentation of the base helper for details.
|
1903
|
+
|
1904
|
+
(field_helpers - [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]).each do |selector|
|
1321
1905
|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
1322
1906
|
def #{selector}(method, options = {}) # def text_field(method, options = {})
|
1323
1907
|
@template.send( # @template.send(
|
@@ -1386,9 +1970,9 @@ module ActionView
|
|
1386
1970
|
# _class_ of the model object, e.g. if <tt>@person.permission</tt>, is
|
1387
1971
|
# of class +Permission+, the field will still be named <tt>permission[admin]</tt>.
|
1388
1972
|
#
|
1389
|
-
# Note: This also works for the methods in
|
1973
|
+
# Note: This also works for the methods in FormOptionsHelper and
|
1390
1974
|
# DateHelper that are designed to work with an object as base, like
|
1391
|
-
#
|
1975
|
+
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
|
1392
1976
|
#
|
1393
1977
|
# === Nested Attributes Examples
|
1394
1978
|
#
|
@@ -1586,19 +2170,37 @@ module ActionView
|
|
1586
2170
|
record_name = model_name_from_record_or_class(record_object).param_key
|
1587
2171
|
end
|
1588
2172
|
|
2173
|
+
object_name = @object_name
|
1589
2174
|
index = if options.has_key?(:index)
|
1590
2175
|
options[:index]
|
1591
2176
|
elsif defined?(@auto_index)
|
1592
|
-
|
2177
|
+
object_name = object_name.to_s.sub(/\[\]$/, "")
|
1593
2178
|
@auto_index
|
1594
2179
|
end
|
1595
2180
|
|
1596
|
-
record_name =
|
2181
|
+
record_name = if index
|
2182
|
+
"#{object_name}[#{index}][#{record_name}]"
|
2183
|
+
elsif record_name.to_s.end_with?("[]")
|
2184
|
+
record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]")
|
2185
|
+
"#{object_name}#{record_name}"
|
2186
|
+
else
|
2187
|
+
"#{object_name}[#{record_name}]"
|
2188
|
+
end
|
1597
2189
|
fields_options[:child_index] = index
|
1598
2190
|
|
1599
2191
|
@template.fields_for(record_name, record_object, fields_options, &block)
|
1600
2192
|
end
|
1601
2193
|
|
2194
|
+
# See the docs for the <tt>ActionView::FormHelper.fields</tt> helper method.
|
2195
|
+
def fields(scope = nil, model: nil, **options, &block)
|
2196
|
+
options[:allow_method_names_outside_object] = true
|
2197
|
+
options[:skip_default_ids] = !FormHelper.form_with_generates_ids
|
2198
|
+
|
2199
|
+
convert_to_legacy_options(options)
|
2200
|
+
|
2201
|
+
fields_for(scope || model, model, options, &block)
|
2202
|
+
end
|
2203
|
+
|
1602
2204
|
# Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
|
1603
2205
|
# assigned to the template (identified by +object+). The text of label will default to the attribute name unless a translation
|
1604
2206
|
# is found in the current I18n locale (through helpers.label.<modelname>.<attribute>) or you specify it explicitly.
|
@@ -1607,7 +2209,7 @@ module ActionView
|
|
1607
2209
|
# target labels for radio_button tags (where the value is used in the ID of the input tag).
|
1608
2210
|
#
|
1609
2211
|
# ==== Examples
|
1610
|
-
# label(:
|
2212
|
+
# label(:title)
|
1611
2213
|
# # => <label for="post_title">Title</label>
|
1612
2214
|
#
|
1613
2215
|
# You can localize your labels based on model and attribute names.
|
@@ -1620,7 +2222,7 @@ module ActionView
|
|
1620
2222
|
#
|
1621
2223
|
# Which then will result in
|
1622
2224
|
#
|
1623
|
-
# label(:
|
2225
|
+
# label(:body)
|
1624
2226
|
# # => <label for="post_body">Write your entire text here</label>
|
1625
2227
|
#
|
1626
2228
|
# Localization can also be based purely on the translation of the attribute-name
|
@@ -1631,21 +2233,22 @@ module ActionView
|
|
1631
2233
|
# post:
|
1632
2234
|
# cost: "Total cost"
|
1633
2235
|
#
|
1634
|
-
# label(:
|
2236
|
+
# label(:cost)
|
1635
2237
|
# # => <label for="post_cost">Total cost</label>
|
1636
2238
|
#
|
1637
|
-
# label(:
|
2239
|
+
# label(:title, "A short title")
|
1638
2240
|
# # => <label for="post_title">A short title</label>
|
1639
2241
|
#
|
1640
|
-
# label(:
|
2242
|
+
# label(:title, "A short title", class: "title_label")
|
1641
2243
|
# # => <label for="post_title" class="title_label">A short title</label>
|
1642
2244
|
#
|
1643
|
-
# label(:
|
2245
|
+
# label(:privacy, "Public Post", value: "public")
|
1644
2246
|
# # => <label for="post_privacy_public">Public Post</label>
|
1645
2247
|
#
|
1646
|
-
# label(:
|
1647
|
-
# 'Accept <a href="/terms">Terms</a>.'
|
2248
|
+
# label(:terms) do
|
2249
|
+
# raw('Accept <a href="/terms">Terms</a>.')
|
1648
2250
|
# end
|
2251
|
+
# # => <label for="post_terms">Accept <a href="/terms">Terms</a>.</label>
|
1649
2252
|
def label(method, text = nil, options = {}, &block)
|
1650
2253
|
@template.label(@object_name, method, text, objectify_options(options), &block)
|
1651
2254
|
end
|
@@ -1694,16 +2297,17 @@ module ActionView
|
|
1694
2297
|
# hashes instead of arrays.
|
1695
2298
|
#
|
1696
2299
|
# # Let's say that @post.validated? is 1:
|
1697
|
-
# check_box("
|
2300
|
+
# check_box("validated")
|
1698
2301
|
# # => <input name="post[validated]" type="hidden" value="0" />
|
1699
2302
|
# # <input checked="checked" type="checkbox" id="post_validated" name="post[validated]" value="1" />
|
1700
2303
|
#
|
1701
2304
|
# # Let's say that @puppy.gooddog is "no":
|
1702
|
-
# check_box("
|
2305
|
+
# check_box("gooddog", {}, "yes", "no")
|
1703
2306
|
# # => <input name="puppy[gooddog]" type="hidden" value="no" />
|
1704
2307
|
# # <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
|
1705
2308
|
#
|
1706
|
-
#
|
2309
|
+
# # Let's say that @eula.accepted is "no":
|
2310
|
+
# check_box("accepted", { class: 'eula_check' }, "yes", "no")
|
1707
2311
|
# # => <input name="eula[accepted]" type="hidden" value="no" />
|
1708
2312
|
# # <input type="checkbox" class="eula_check" id="eula_accepted" name="eula[accepted]" value="yes" />
|
1709
2313
|
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
@@ -1718,13 +2322,14 @@ module ActionView
|
|
1718
2322
|
# +options+ hash. You may pass HTML options there as well.
|
1719
2323
|
#
|
1720
2324
|
# # Let's say that @post.category returns "rails":
|
1721
|
-
# radio_button("
|
1722
|
-
# radio_button("
|
2325
|
+
# radio_button("category", "rails")
|
2326
|
+
# radio_button("category", "java")
|
1723
2327
|
# # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" />
|
1724
2328
|
# # <input type="radio" id="post_category_java" name="post[category]" value="java" />
|
1725
2329
|
#
|
1726
|
-
#
|
1727
|
-
# radio_button("
|
2330
|
+
# # Let's say that @user.receive_newsletter returns "no":
|
2331
|
+
# radio_button("receive_newsletter", "yes")
|
2332
|
+
# radio_button("receive_newsletter", "no")
|
1728
2333
|
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
|
1729
2334
|
# # <input type="radio" id="user_receive_newsletter_no" name="user[receive_newsletter]" value="no" checked="checked" />
|
1730
2335
|
def radio_button(method, tag_value, options = {})
|
@@ -1737,14 +2342,17 @@ module ActionView
|
|
1737
2342
|
# shown.
|
1738
2343
|
#
|
1739
2344
|
# ==== Examples
|
1740
|
-
#
|
1741
|
-
#
|
2345
|
+
# # Let's say that @signup.pass_confirm returns true:
|
2346
|
+
# hidden_field(:pass_confirm)
|
2347
|
+
# # => <input type="hidden" id="signup_pass_confirm" name="signup[pass_confirm]" value="true" />
|
1742
2348
|
#
|
1743
|
-
#
|
1744
|
-
#
|
2349
|
+
# # Let's say that @post.tag_list returns "blog, ruby":
|
2350
|
+
# hidden_field(:tag_list)
|
2351
|
+
# # => <input type="hidden" id="post_tag_list" name="post[tag_list]" value="blog, ruby" />
|
1745
2352
|
#
|
1746
|
-
#
|
1747
|
-
#
|
2353
|
+
# # Let's say that @user.token returns "abcde":
|
2354
|
+
# hidden_field(:token)
|
2355
|
+
# # => <input type="hidden" id="user_token" name="user[token]" value="abcde" />
|
1748
2356
|
#
|
1749
2357
|
def hidden_field(method, options = {})
|
1750
2358
|
@emitted_hidden_id = true if method == :id
|
@@ -1765,19 +2373,24 @@ module ActionView
|
|
1765
2373
|
# * <tt>:accept</tt> - If set to one or multiple mime-types, the user will be suggested a filter when choosing a file. You still need to set up model validations.
|
1766
2374
|
#
|
1767
2375
|
# ==== Examples
|
1768
|
-
#
|
2376
|
+
# # Let's say that @user has avatar:
|
2377
|
+
# file_field(:avatar)
|
1769
2378
|
# # => <input type="file" id="user_avatar" name="user[avatar]" />
|
1770
2379
|
#
|
1771
|
-
#
|
1772
|
-
#
|
2380
|
+
# # Let's say that @post has image:
|
2381
|
+
# file_field(:image, :multiple => true)
|
2382
|
+
# # => <input type="file" id="post_image" name="post[image][]" multiple="multiple" />
|
1773
2383
|
#
|
1774
|
-
#
|
2384
|
+
# # Let's say that @post has attached:
|
2385
|
+
# file_field(:attached, accept: 'text/html')
|
1775
2386
|
# # => <input accept="text/html" type="file" id="post_attached" name="post[attached]" />
|
1776
2387
|
#
|
1777
|
-
#
|
2388
|
+
# # Let's say that @post has image:
|
2389
|
+
# file_field(:image, accept: 'image/png,image/gif,image/jpeg')
|
1778
2390
|
# # => <input type="file" id="post_image" name="post[image]" accept="image/png,image/gif,image/jpeg" />
|
1779
2391
|
#
|
1780
|
-
#
|
2392
|
+
# # Let's say that @attachment has file:
|
2393
|
+
# file_field(:file, class: 'file_input')
|
1781
2394
|
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
|
1782
2395
|
def file_field(method, options = {})
|
1783
2396
|
self.multipart = true
|
@@ -1791,11 +2404,11 @@ module ActionView
|
|
1791
2404
|
# <%= f.submit %>
|
1792
2405
|
# <% end %>
|
1793
2406
|
#
|
1794
|
-
# In the example above, if
|
1795
|
-
# submit button label
|
2407
|
+
# In the example above, if <tt>@post</tt> is a new record, it will use "Create Post" as
|
2408
|
+
# submit button label; otherwise, it uses "Update Post".
|
1796
2409
|
#
|
1797
|
-
# Those labels can be customized using I18n
|
1798
|
-
#
|
2410
|
+
# Those labels can be customized using I18n under the +helpers.submit+ key and using
|
2411
|
+
# <tt>%{model}</tt> for translation interpolation:
|
1799
2412
|
#
|
1800
2413
|
# en:
|
1801
2414
|
# helpers:
|
@@ -1803,7 +2416,7 @@ module ActionView
|
|
1803
2416
|
# create: "Create a %{model}"
|
1804
2417
|
# update: "Confirm changes to %{model}"
|
1805
2418
|
#
|
1806
|
-
# It also searches for a key specific
|
2419
|
+
# It also searches for a key specific to the given object:
|
1807
2420
|
#
|
1808
2421
|
# en:
|
1809
2422
|
# helpers:
|
@@ -1811,7 +2424,7 @@ module ActionView
|
|
1811
2424
|
# post:
|
1812
2425
|
# create: "Add %{model}"
|
1813
2426
|
#
|
1814
|
-
def submit(value=nil, options={})
|
2427
|
+
def submit(value = nil, options = {})
|
1815
2428
|
value, options = nil, value if value.is_a?(Hash)
|
1816
2429
|
value ||= submit_default_value
|
1817
2430
|
@template.submit_tag(value, options)
|
@@ -1824,11 +2437,11 @@ module ActionView
|
|
1824
2437
|
# <%= f.button %>
|
1825
2438
|
# <% end %>
|
1826
2439
|
#
|
1827
|
-
# In the example above, if
|
1828
|
-
# button label
|
2440
|
+
# In the example above, if <tt>@post</tt> is a new record, it will use "Create Post" as
|
2441
|
+
# button label; otherwise, it uses "Update Post".
|
1829
2442
|
#
|
1830
|
-
# Those labels can be customized using I18n
|
1831
|
-
# (the same as submit helper) and
|
2443
|
+
# Those labels can be customized using I18n under the +helpers.submit+ key
|
2444
|
+
# (the same as submit helper) and using <tt>%{model}</tt> for translation interpolation:
|
1832
2445
|
#
|
1833
2446
|
# en:
|
1834
2447
|
# helpers:
|
@@ -1836,7 +2449,7 @@ module ActionView
|
|
1836
2449
|
# create: "Create a %{model}"
|
1837
2450
|
# update: "Confirm changes to %{model}"
|
1838
2451
|
#
|
1839
|
-
# It also searches for a key specific
|
2452
|
+
# It also searches for a key specific to the given object:
|
1840
2453
|
#
|
1841
2454
|
# en:
|
1842
2455
|
# helpers:
|
@@ -1845,7 +2458,7 @@ module ActionView
|
|
1845
2458
|
# create: "Add %{model}"
|
1846
2459
|
#
|
1847
2460
|
# ==== Examples
|
1848
|
-
# button("Create
|
2461
|
+
# button("Create post")
|
1849
2462
|
# # => <button name='button' type='submit'>Create post</button>
|
1850
2463
|
#
|
1851
2464
|
# button do
|
@@ -1861,7 +2474,7 @@ module ActionView
|
|
1861
2474
|
@template.button_tag(value, options, &block)
|
1862
2475
|
end
|
1863
2476
|
|
1864
|
-
def emitted_hidden_id?
|
2477
|
+
def emitted_hidden_id? # :nodoc:
|
1865
2478
|
@emitted_hidden_id ||= nil
|
1866
2479
|
end
|
1867
2480
|
|
@@ -1881,7 +2494,12 @@ module ActionView
|
|
1881
2494
|
end
|
1882
2495
|
|
1883
2496
|
defaults = []
|
1884
|
-
|
2497
|
+
# Object is a model and it is not overwritten by as and scope option.
|
2498
|
+
if object.respond_to?(:model_name) && object_name.to_s == model.downcase
|
2499
|
+
defaults << :"helpers.submit.#{object.model_name.i18n_key}.#{key}"
|
2500
|
+
else
|
2501
|
+
defaults << :"helpers.submit.#{object_name}.#{key}"
|
2502
|
+
end
|
1885
2503
|
defaults << :"helpers.submit.#{key}"
|
1886
2504
|
defaults << "#{key.to_s.humanize} #{model}"
|
1887
2505
|
|
@@ -1906,7 +2524,11 @@ module ActionView
|
|
1906
2524
|
explicit_child_index = options[:child_index]
|
1907
2525
|
output = ActiveSupport::SafeBuffer.new
|
1908
2526
|
association.each do |child|
|
1909
|
-
|
2527
|
+
if explicit_child_index
|
2528
|
+
options[:child_index] = explicit_child_index.call if explicit_child_index.respond_to?(:call)
|
2529
|
+
else
|
2530
|
+
options[:child_index] = nested_child_index(name)
|
2531
|
+
end
|
1910
2532
|
output << fields_for_nested_model("#{name}[#{options[:child_index]}]", child, options, block)
|
1911
2533
|
end
|
1912
2534
|
output
|
@@ -1932,12 +2554,16 @@ module ActionView
|
|
1932
2554
|
@nested_child_index[name] ||= -1
|
1933
2555
|
@nested_child_index[name] += 1
|
1934
2556
|
end
|
2557
|
+
|
2558
|
+
def convert_to_legacy_options(options)
|
2559
|
+
if options.key?(:skip_id)
|
2560
|
+
options[:include_id] = !options.delete(:skip_id)
|
2561
|
+
end
|
2562
|
+
end
|
1935
2563
|
end
|
1936
2564
|
end
|
1937
2565
|
|
1938
2566
|
ActiveSupport.on_load(:action_view) do
|
1939
|
-
cattr_accessor
|
1940
|
-
::ActionView::Helpers::FormBuilder
|
1941
|
-
end
|
2567
|
+
cattr_accessor :default_form_builder, instance_writer: false, instance_reader: false, default: ::ActionView::Helpers::FormBuilder
|
1942
2568
|
end
|
1943
2569
|
end
|