actionview 4.2.10 → 5.1.0
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 +141 -272
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/action_view/base.rb +33 -21
- data/lib/action_view/buffers.rb +1 -1
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/dependency_tracker.rb +52 -20
- data/lib/action_view/digestor.rb +86 -83
- data/lib/action_view/flows.rb +9 -11
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/active_model_helper.rb +8 -8
- data/lib/action_view/helpers/asset_tag_helper.rb +74 -38
- data/lib/action_view/helpers/asset_url_helper.rb +160 -59
- data/lib/action_view/helpers/atom_feed_helper.rb +16 -16
- data/lib/action_view/helpers/cache_helper.rb +90 -35
- data/lib/action_view/helpers/capture_helper.rb +7 -6
- data/lib/action_view/helpers/controller_helper.rb +3 -2
- data/lib/action_view/helpers/csrf_helper.rb +3 -3
- data/lib/action_view/helpers/date_helper.rb +156 -108
- data/lib/action_view/helpers/debug_helper.rb +3 -4
- data/lib/action_view/helpers/form_helper.rb +475 -94
- data/lib/action_view/helpers/form_options_helper.rb +87 -47
- data/lib/action_view/helpers/form_tag_helper.rb +88 -57
- data/lib/action_view/helpers/javascript_helper.rb +10 -10
- data/lib/action_view/helpers/number_helper.rb +76 -59
- data/lib/action_view/helpers/output_safety_helper.rb +34 -4
- data/lib/action_view/helpers/record_tag_helper.rb +12 -99
- data/lib/action_view/helpers/rendering_helper.rb +3 -3
- data/lib/action_view/helpers/sanitize_helper.rb +17 -14
- data/lib/action_view/helpers/tag_helper.rb +198 -73
- data/lib/action_view/helpers/tags/base.rb +132 -97
- data/lib/action_view/helpers/tags/check_box.rb +17 -17
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +9 -33
- data/lib/action_view/helpers/tags/collection_helpers.rb +68 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +3 -11
- data/lib/action_view/helpers/tags/collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/date_select.rb +36 -36
- data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/label.rb +5 -1
- data/lib/action_view/helpers/tags/password_field.rb +1 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
- data/lib/action_view/helpers/tags/radio_button.rb +4 -4
- data/lib/action_view/helpers/tags/search_field.rb +12 -9
- data/lib/action_view/helpers/tags/select.rb +9 -9
- data/lib/action_view/helpers/tags/text_area.rb +1 -1
- data/lib/action_view/helpers/tags/text_field.rb +5 -6
- data/lib/action_view/helpers/tags/translator.rb +15 -13
- data/lib/action_view/helpers/text_helper.rb +47 -30
- data/lib/action_view/helpers/translation_helper.rb +60 -30
- data/lib/action_view/helpers/url_helper.rb +132 -104
- data/lib/action_view/helpers.rb +1 -1
- data/lib/action_view/layouts.rb +59 -54
- data/lib/action_view/log_subscriber.rb +56 -7
- data/lib/action_view/lookup_context.rb +76 -61
- data/lib/action_view/model_naming.rb +1 -1
- data/lib/action_view/path_set.rb +28 -19
- data/lib/action_view/railtie.rb +30 -6
- data/lib/action_view/record_identifier.rb +51 -25
- data/lib/action_view/renderer/abstract_renderer.rb +19 -15
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +55 -0
- data/lib/action_view/renderer/partial_renderer.rb +208 -206
- data/lib/action_view/renderer/renderer.rb +2 -6
- data/lib/action_view/renderer/streaming_template_renderer.rb +46 -48
- data/lib/action_view/renderer/template_renderer.rb +65 -66
- data/lib/action_view/rendering.rb +16 -9
- data/lib/action_view/routing_url_for.rb +25 -17
- data/lib/action_view/tasks/cache_digests.rake +23 -0
- data/lib/action_view/template/error.rb +14 -13
- data/lib/action_view/template/handlers/builder.rb +7 -7
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
- data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
- data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
- data/lib/action_view/template/handlers/erb.rb +9 -76
- data/lib/action_view/template/handlers/html.rb +9 -0
- data/lib/action_view/template/handlers/raw.rb +1 -3
- data/lib/action_view/template/handlers.rb +8 -6
- data/lib/action_view/template/html.rb +2 -4
- data/lib/action_view/template/resolver.rb +133 -109
- data/lib/action_view/template/text.rb +5 -8
- data/lib/action_view/template/types.rb +15 -17
- data/lib/action_view/template.rb +51 -28
- data/lib/action_view/test_case.rb +32 -27
- data/lib/action_view/testing/resolvers.rb +29 -31
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +26 -32
- data/lib/action_view.rb +5 -5
- data/lib/assets/compiled/rails-ujs.js +685 -0
- metadata +23 -23
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,13 +1,14 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
1
|
+
require "cgi"
|
2
|
+
require "action_view/helpers/date_helper"
|
3
|
+
require "action_view/helpers/tag_helper"
|
4
|
+
require "action_view/helpers/form_tag_helper"
|
5
|
+
require "action_view/helpers/active_model_helper"
|
6
|
+
require "action_view/model_naming"
|
7
|
+
require "action_view/record_identifier"
|
8
|
+
require "active_support/core_ext/module/attribute_accessors"
|
9
|
+
require "active_support/core_ext/hash/slice"
|
10
|
+
require "active_support/core_ext/string/output_safety"
|
11
|
+
require "active_support/core_ext/string/inflections"
|
11
12
|
|
12
13
|
module ActionView
|
13
14
|
# = Action View Form Helpers
|
@@ -66,9 +67,10 @@ module ActionView
|
|
66
67
|
#
|
67
68
|
# In particular, thanks to the conventions followed in the generated field names, the
|
68
69
|
# 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.
|
70
|
+
# set in the form. That hash is ready to be passed to <tt>Person.new</tt>:
|
70
71
|
#
|
71
|
-
#
|
72
|
+
# @person = Person.new(params[:person])
|
73
|
+
# if @person.save
|
72
74
|
# # success
|
73
75
|
# else
|
74
76
|
# # error handling
|
@@ -110,6 +112,9 @@ module ActionView
|
|
110
112
|
include FormTagHelper
|
111
113
|
include UrlHelper
|
112
114
|
include ModelNaming
|
115
|
+
include RecordIdentifier
|
116
|
+
|
117
|
+
attr_internal :default_form_builder
|
113
118
|
|
114
119
|
# Creates a form that allows the user to create or update the attributes
|
115
120
|
# of a specific model object.
|
@@ -138,6 +143,7 @@ module ActionView
|
|
138
143
|
# will get expanded to
|
139
144
|
#
|
140
145
|
# <%= text_field :person, :first_name %>
|
146
|
+
#
|
141
147
|
# which results in an HTML <tt><input></tt> tag whose +name+ attribute is
|
142
148
|
# <tt>person[first_name]</tt>. This means that when the form is submitted,
|
143
149
|
# the value entered by the user will be available in the controller as
|
@@ -461,13 +467,275 @@ module ActionView
|
|
461
467
|
)
|
462
468
|
|
463
469
|
options[:url] ||= if options.key?(:format)
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
470
|
+
polymorphic_path(record, format: options.delete(:format))
|
471
|
+
else
|
472
|
+
polymorphic_path(record, {})
|
473
|
+
end
|
468
474
|
end
|
469
475
|
private :apply_form_for_options!
|
470
476
|
|
477
|
+
mattr_accessor(:form_with_generates_remote_forms) { true }
|
478
|
+
|
479
|
+
# Creates a form tag based on mixing URLs, scopes, or models.
|
480
|
+
#
|
481
|
+
# # Using just a URL:
|
482
|
+
# <%= form_with url: posts_path do |form| %>
|
483
|
+
# <%= form.text_field :title %>
|
484
|
+
# <% end %>
|
485
|
+
# # =>
|
486
|
+
# <form action="/posts" method="post" data-remote="true">
|
487
|
+
# <input type="text" name="title">
|
488
|
+
# </form>
|
489
|
+
#
|
490
|
+
# # Adding a scope prefixes the input field names:
|
491
|
+
# <%= form_with scope: :post, url: posts_path do |form| %>
|
492
|
+
# <%= form.text_field :title %>
|
493
|
+
# <% end %>
|
494
|
+
# # =>
|
495
|
+
# <form action="/posts" method="post" data-remote="true">
|
496
|
+
# <input type="text" name="post[title]">
|
497
|
+
# </form>
|
498
|
+
#
|
499
|
+
# # Using a model infers both the URL and scope:
|
500
|
+
# <%= form_with model: Post.new do |form| %>
|
501
|
+
# <%= form.text_field :title %>
|
502
|
+
# <% end %>
|
503
|
+
# # =>
|
504
|
+
# <form action="/posts" method="post" data-remote="true">
|
505
|
+
# <input type="text" name="post[title]">
|
506
|
+
# </form>
|
507
|
+
#
|
508
|
+
# # An existing model makes an update form and fills out field values:
|
509
|
+
# <%= form_with model: Post.first do |form| %>
|
510
|
+
# <%= form.text_field :title %>
|
511
|
+
# <% end %>
|
512
|
+
# # =>
|
513
|
+
# <form action="/posts/1" method="post" data-remote="true">
|
514
|
+
# <input type="hidden" name="_method" value="patch">
|
515
|
+
# <input type="text" name="post[title]" value="<the title of the post>">
|
516
|
+
# </form>
|
517
|
+
#
|
518
|
+
# # Though the fields don't have to correspond to model attributes:
|
519
|
+
# <%= form_with model: Cat.new do |form| %>
|
520
|
+
# <%= form.text_field :cats_dont_have_gills %>
|
521
|
+
# <%= form.text_field :but_in_forms_they_can %>
|
522
|
+
# <% end %>
|
523
|
+
# # =>
|
524
|
+
# <form action="/cats" method="post" data-remote="true">
|
525
|
+
# <input type="text" name="cat[cats_dont_have_gills]">
|
526
|
+
# <input type="text" name="cat[but_in_forms_they_can]">
|
527
|
+
# </form>
|
528
|
+
#
|
529
|
+
# The parameters in the forms are accessible in controllers according to
|
530
|
+
# their name nesting. So inputs named +title+ and <tt>post[title]</tt> are
|
531
|
+
# accessible as <tt>params[:title]</tt> and <tt>params[:post][:title]</tt>
|
532
|
+
# respectively.
|
533
|
+
#
|
534
|
+
# By default +form_with+ attaches the <tt>data-remote</tt> attribute
|
535
|
+
# submitting the form via an XMLHTTPRequest in the background if an
|
536
|
+
# Unobtrusive JavaScript driver, like rails-ujs, is used. See the
|
537
|
+
# <tt>:local</tt> option for more.
|
538
|
+
#
|
539
|
+
# For ease of comparison the examples above left out the submit button,
|
540
|
+
# as well as the auto generated hidden fields that enable UTF-8 support
|
541
|
+
# and adds an authenticity token needed for cross site request forgery
|
542
|
+
# protection.
|
543
|
+
#
|
544
|
+
# ==== +form_with+ options
|
545
|
+
#
|
546
|
+
# * <tt>:url</tt> - The URL the form submits to. Akin to values passed to
|
547
|
+
# +url_for+ or +link_to+. For example, you may use a named route
|
548
|
+
# directly. When a <tt>:scope</tt> is passed without a <tt>:url</tt> the
|
549
|
+
# form just submits to the current URL.
|
550
|
+
# * <tt>:method</tt> - The method to use when submitting the form, usually
|
551
|
+
# either "get" or "post". If "patch", "put", "delete", or another verb
|
552
|
+
# is used, a hidden input named <tt>_method</tt> is added to
|
553
|
+
# simulate the verb over post.
|
554
|
+
# * <tt>:format</tt> - The format of the route the form submits to.
|
555
|
+
# Useful when submitting to another resource type, like <tt>:json</tt>.
|
556
|
+
# Skipped if a <tt>:url</tt> is passed.
|
557
|
+
# * <tt>:scope</tt> - The scope to prefix input field names with and
|
558
|
+
# thereby how the submitted parameters are grouped in controllers.
|
559
|
+
# * <tt>:model</tt> - A model object to infer the <tt>:url</tt> and
|
560
|
+
# <tt>:scope</tt> by, plus fill out input field values.
|
561
|
+
# So if a +title+ attribute is set to "Ahoy!" then a +title+ input
|
562
|
+
# field's value would be "Ahoy!".
|
563
|
+
# If the model is a new record a create form is generated, if an
|
564
|
+
# existing record, however, an update form is generated.
|
565
|
+
# Pass <tt>:scope</tt> or <tt>:url</tt> to override the defaults.
|
566
|
+
# E.g. turn <tt>params[:post]</tt> into <tt>params[:article]</tt>.
|
567
|
+
# * <tt>:authenticity_token</tt> - Authenticity token to use in the form.
|
568
|
+
# Override with a custom authenticity token or pass <tt>false</tt> to
|
569
|
+
# skip the authenticity token field altogether.
|
570
|
+
# Useful when submitting to an external resource like a payment gateway
|
571
|
+
# that might limit the valid fields.
|
572
|
+
# Remote forms may omit the embedded authenticity token by setting
|
573
|
+
# <tt>config.action_view.embed_authenticity_token_in_remote_forms = false</tt>.
|
574
|
+
# This is helpful when fragment-caching the form. Remote forms
|
575
|
+
# get the authenticity token from the <tt>meta</tt> tag, so embedding is
|
576
|
+
# unnecessary unless you support browsers without JavaScript.
|
577
|
+
# * <tt>:local</tt> - By default form submits are remote and unobstrusive XHRs.
|
578
|
+
# Disable remote submits with <tt>local: true</tt>.
|
579
|
+
# * <tt>:skip_enforcing_utf8</tt> - By default a hidden field named +utf8+
|
580
|
+
# is output to enforce UTF-8 submits. Set to true to skip the field.
|
581
|
+
# * <tt>:builder</tt> - Override the object used to build the form.
|
582
|
+
# * <tt>:id</tt> - Optional HTML id attribute.
|
583
|
+
# * <tt>:class</tt> - Optional HTML class attribute.
|
584
|
+
# * <tt>:data</tt> - Optional HTML data attributes.
|
585
|
+
# * <tt>:html</tt> - Other optional HTML attributes for the form tag.
|
586
|
+
#
|
587
|
+
# === Examples
|
588
|
+
#
|
589
|
+
# When not passing a block, +form_with+ just generates an opening form tag.
|
590
|
+
#
|
591
|
+
# <%= form_with(model: @post, url: super_posts_path) %>
|
592
|
+
# <%= form_with(model: @post, scope: :article) %>
|
593
|
+
# <%= form_with(model: @post, format: :json) %>
|
594
|
+
# <%= form_with(model: @post, authenticity_token: false) %> # Disables the token.
|
595
|
+
#
|
596
|
+
# For namespaced routes, like +admin_post_url+:
|
597
|
+
#
|
598
|
+
# <%= form_with(model: [ :admin, @post ]) do |form| %>
|
599
|
+
# ...
|
600
|
+
# <% end %>
|
601
|
+
#
|
602
|
+
# If your resource has associations defined, for example, you want to add comments
|
603
|
+
# to the document given that the routes are set correctly:
|
604
|
+
#
|
605
|
+
# <%= form_with(model: [ @document, Comment.new ]) do |form| %>
|
606
|
+
# ...
|
607
|
+
# <% end %>
|
608
|
+
#
|
609
|
+
# Where <tt>@document = Document.find(params[:id])</tt>.
|
610
|
+
#
|
611
|
+
# When using labels +form_with+ requires setting the id on the field being
|
612
|
+
# labelled:
|
613
|
+
#
|
614
|
+
# <%= form_with(model: @post) do |form| %>
|
615
|
+
# <%= form.label :title %>
|
616
|
+
# <%= form.text_field :title, id: :post_title %>
|
617
|
+
# <% end %>
|
618
|
+
#
|
619
|
+
# See +label+ for more on how the +for+ attribute is derived.
|
620
|
+
#
|
621
|
+
# === Mixing with other form helpers
|
622
|
+
#
|
623
|
+
# While +form_with+ uses a FormBuilder object it's possible to mix and
|
624
|
+
# match the stand-alone FormHelper methods and methods
|
625
|
+
# from FormTagHelper:
|
626
|
+
#
|
627
|
+
# <%= form_with scope: :person do |form| %>
|
628
|
+
# <%= form.text_field :first_name %>
|
629
|
+
# <%= form.text_field :last_name %>
|
630
|
+
#
|
631
|
+
# <%= text_area :person, :biography %>
|
632
|
+
# <%= check_box_tag "person[admin]", "1", @person.company.admin? %>
|
633
|
+
#
|
634
|
+
# <%= form.submit %>
|
635
|
+
# <% end %>
|
636
|
+
#
|
637
|
+
# Same goes for the methods in FormOptionHelper and DateHelper designed
|
638
|
+
# to work with an object as a base, like
|
639
|
+
# FormOptionHelper#collection_select and DateHelper#datetime_select.
|
640
|
+
#
|
641
|
+
# === Setting the method
|
642
|
+
#
|
643
|
+
# You can force the form to use the full array of HTTP verbs by setting
|
644
|
+
#
|
645
|
+
# method: (:get|:post|:patch|:put|:delete)
|
646
|
+
#
|
647
|
+
# in the options hash. If the verb is not GET or POST, which are natively
|
648
|
+
# supported by HTML forms, the form will be set to POST and a hidden input
|
649
|
+
# called _method will carry the intended verb for the server to interpret.
|
650
|
+
#
|
651
|
+
# === Setting HTML options
|
652
|
+
#
|
653
|
+
# You can set data attributes directly in a data hash, but HTML options
|
654
|
+
# besides id and class must be wrapped in an HTML key:
|
655
|
+
#
|
656
|
+
# <%= form_with(model: @post, data: { behavior: "autosave" }, html: { name: "go" }) do |form| %>
|
657
|
+
# ...
|
658
|
+
# <% end %>
|
659
|
+
#
|
660
|
+
# generates
|
661
|
+
#
|
662
|
+
# <form action="/posts/123" method="post" data-behavior="autosave" name="go">
|
663
|
+
# <input name="_method" type="hidden" value="patch" />
|
664
|
+
# ...
|
665
|
+
# </form>
|
666
|
+
#
|
667
|
+
# === Removing hidden model id's
|
668
|
+
#
|
669
|
+
# The +form_with+ method automatically includes the model id as a hidden field in the form.
|
670
|
+
# This is used to maintain the correlation between the form data and its associated model.
|
671
|
+
# Some ORM systems do not use IDs on nested models so in this case you want to be able
|
672
|
+
# to disable the hidden id.
|
673
|
+
#
|
674
|
+
# In the following example the Post model has many Comments stored within it in a NoSQL database,
|
675
|
+
# thus there is no primary key for comments.
|
676
|
+
#
|
677
|
+
# <%= form_with(model: @post) do |form| %>
|
678
|
+
# <%= form.fields(:comments, skip_id: true) do |fields| %>
|
679
|
+
# ...
|
680
|
+
# <% end %>
|
681
|
+
# <% end %>
|
682
|
+
#
|
683
|
+
# === Customized form builders
|
684
|
+
#
|
685
|
+
# You can also build forms using a customized FormBuilder class. Subclass
|
686
|
+
# FormBuilder and override or define some more helpers, then use your
|
687
|
+
# custom builder. For example, let's say you made a helper to
|
688
|
+
# automatically add labels to form inputs.
|
689
|
+
#
|
690
|
+
# <%= form_with model: @person, url: { action: "create" }, builder: LabellingFormBuilder do |form| %>
|
691
|
+
# <%= form.text_field :first_name %>
|
692
|
+
# <%= form.text_field :last_name %>
|
693
|
+
# <%= form.text_area :biography %>
|
694
|
+
# <%= form.check_box :admin %>
|
695
|
+
# <%= form.submit %>
|
696
|
+
# <% end %>
|
697
|
+
#
|
698
|
+
# In this case, if you use:
|
699
|
+
#
|
700
|
+
# <%= render form %>
|
701
|
+
#
|
702
|
+
# The rendered template is <tt>people/_labelling_form</tt> and the local
|
703
|
+
# variable referencing the form builder is called
|
704
|
+
# <tt>labelling_form</tt>.
|
705
|
+
#
|
706
|
+
# The custom FormBuilder class is automatically merged with the options
|
707
|
+
# of a nested +fields+ call, unless it's explicitly set.
|
708
|
+
#
|
709
|
+
# In many cases you will want to wrap the above in another helper, so you
|
710
|
+
# could do something like the following:
|
711
|
+
#
|
712
|
+
# def labelled_form_with(**options, &block)
|
713
|
+
# form_with(**options.merge(builder: LabellingFormBuilder), &block)
|
714
|
+
# end
|
715
|
+
def form_with(model: nil, scope: nil, url: nil, format: nil, **options)
|
716
|
+
options[:allow_method_names_outside_object] = true
|
717
|
+
options[:skip_default_ids] = true
|
718
|
+
|
719
|
+
if model
|
720
|
+
url ||= polymorphic_path(model, format: format)
|
721
|
+
|
722
|
+
model = model.last if model.is_a?(Array)
|
723
|
+
scope ||= model_name_from_record_or_class(model).param_key
|
724
|
+
end
|
725
|
+
|
726
|
+
if block_given?
|
727
|
+
builder = instantiate_builder(scope, model, options)
|
728
|
+
output = capture(builder, &Proc.new)
|
729
|
+
options[:multipart] ||= builder.multipart?
|
730
|
+
|
731
|
+
html_options = html_options_for_form_with(url, model, options)
|
732
|
+
form_tag_with_body(html_options, output)
|
733
|
+
else
|
734
|
+
html_options = html_options_for_form_with(url, model, options)
|
735
|
+
form_tag_html(html_options)
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
471
739
|
# Creates a scope around a specific model object like form_for, but
|
472
740
|
# doesn't create the form tags themselves. This makes fields_for suitable
|
473
741
|
# for specifying additional model objects in the same form.
|
@@ -714,6 +982,74 @@ module ActionView
|
|
714
982
|
capture(builder, &block)
|
715
983
|
end
|
716
984
|
|
985
|
+
# Scopes input fields with either an explicit scope or model.
|
986
|
+
# Like +form_with+ does with <tt>:scope</tt> or <tt>:model</tt>,
|
987
|
+
# except it doesn't output the form tags.
|
988
|
+
#
|
989
|
+
# # Using a scope prefixes the input field names:
|
990
|
+
# <%= fields :comment do |fields| %>
|
991
|
+
# <%= fields.text_field :body %>
|
992
|
+
# <% end %>
|
993
|
+
# # => <input type="text" name="comment[body]>
|
994
|
+
#
|
995
|
+
# # Using a model infers the scope and assigns field values:
|
996
|
+
# <%= fields model: Comment.new(body: "full bodied") do |fields| %<
|
997
|
+
# <%= fields.text_field :body %>
|
998
|
+
# <% end %>
|
999
|
+
# # =>
|
1000
|
+
# <input type="text" name="comment[body] value="full bodied">
|
1001
|
+
#
|
1002
|
+
# # Using +fields+ with +form_with+:
|
1003
|
+
# <%= form_with model: @post do |form| %>
|
1004
|
+
# <%= form.text_field :title %>
|
1005
|
+
#
|
1006
|
+
# <%= form.fields :comment do |fields| %>
|
1007
|
+
# <%= fields.text_field :body %>
|
1008
|
+
# <% end %>
|
1009
|
+
# <% end %>
|
1010
|
+
#
|
1011
|
+
# Much like +form_with+ a FormBuilder instance associated with the scope
|
1012
|
+
# or model is yielded, so any generated field names are prefixed with
|
1013
|
+
# either the passed scope or the scope inferred from the <tt>:model</tt>.
|
1014
|
+
#
|
1015
|
+
# When using labels +fields+ requires setting the id on the field being
|
1016
|
+
# labelled:
|
1017
|
+
#
|
1018
|
+
# <%= fields :comment do |fields| %>
|
1019
|
+
# <%= fields.label :body %>
|
1020
|
+
# <%= fields.text_field :body, id: :comment_body %>
|
1021
|
+
# <% end %>
|
1022
|
+
#
|
1023
|
+
# See +label+ for more on how the +for+ attribute is derived.
|
1024
|
+
#
|
1025
|
+
# === Mixing with other form helpers
|
1026
|
+
#
|
1027
|
+
# While +form_with+ uses a FormBuilder object it's possible to mix and
|
1028
|
+
# match the stand-alone FormHelper methods and methods
|
1029
|
+
# from FormTagHelper:
|
1030
|
+
#
|
1031
|
+
# <%= fields model: @comment do |fields| %>
|
1032
|
+
# <%= fields.text_field :body %>
|
1033
|
+
#
|
1034
|
+
# <%= text_area :commenter, :biography %>
|
1035
|
+
# <%= check_box_tag "comment[all_caps]", "1", @comment.commenter.hulk_mode? %>
|
1036
|
+
# <% end %>
|
1037
|
+
#
|
1038
|
+
# Same goes for the methods in FormOptionHelper and DateHelper designed
|
1039
|
+
# to work with an object as a base, like
|
1040
|
+
# FormOptionHelper#collection_select and DateHelper#datetime_select.
|
1041
|
+
def fields(scope = nil, model: nil, **options, &block)
|
1042
|
+
options[:allow_method_names_outside_object] = true
|
1043
|
+
options[:skip_default_ids] = true
|
1044
|
+
|
1045
|
+
if model
|
1046
|
+
scope ||= model_name_from_record_or_class(model).param_key
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
builder = instantiate_builder(scope, model, options)
|
1050
|
+
capture(builder, &block)
|
1051
|
+
end
|
1052
|
+
|
717
1053
|
# Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
|
718
1054
|
# assigned to the template (identified by +object+). The text of label will default to the attribute name unless a translation
|
719
1055
|
# is found in the current I18n locale (through helpers.label.<modelname>.<attribute>) or you specify it explicitly.
|
@@ -759,7 +1095,7 @@ module ActionView
|
|
759
1095
|
# # => <label for="post_privacy_public">Public Post</label>
|
760
1096
|
#
|
761
1097
|
# label(:post, :terms) do
|
762
|
-
# 'Accept <a href="/terms">Terms</a>.'
|
1098
|
+
# raw('Accept <a href="/terms">Terms</a>.')
|
763
1099
|
# end
|
764
1100
|
# # => <label for="post_terms">Accept <a href="/terms">Terms</a>.</label>
|
765
1101
|
def label(object_name, method, content_or_options = nil, options = nil, &block)
|
@@ -843,8 +1179,8 @@ module ActionView
|
|
843
1179
|
# file_field(:user, :avatar)
|
844
1180
|
# # => <input type="file" id="user_avatar" name="user[avatar]" />
|
845
1181
|
#
|
846
|
-
# file_field(:post, :image, :
|
847
|
-
# # => <input type="file" id="post_image" name="post[image]" multiple="
|
1182
|
+
# file_field(:post, :image, multiple: true)
|
1183
|
+
# # => <input type="file" id="post_image" name="post[image][]" multiple="multiple" />
|
848
1184
|
#
|
849
1185
|
# file_field(:post, :attached, accept: 'text/html')
|
850
1186
|
# # => <input accept="text/html" type="file" id="post_attached" name="post[attached]" />
|
@@ -959,6 +1295,7 @@ module ActionView
|
|
959
1295
|
# # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" />
|
960
1296
|
# # <input type="radio" id="post_category_java" name="post[category]" value="java" />
|
961
1297
|
#
|
1298
|
+
# # Let's say that @user.receive_newsletter returns "no":
|
962
1299
|
# radio_button("user", "receive_newsletter", "yes")
|
963
1300
|
# radio_button("user", "receive_newsletter", "no")
|
964
1301
|
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
|
@@ -1014,7 +1351,7 @@ module ActionView
|
|
1014
1351
|
# date_field("user", "born_on")
|
1015
1352
|
# # => <input id="user_born_on" name="user[born_on]" type="date" />
|
1016
1353
|
#
|
1017
|
-
# The default value is generated by trying to call "
|
1354
|
+
# The default value is generated by trying to call +strftime+ with "%Y-%m-%d"
|
1018
1355
|
# on the object's value, which makes it behave as expected for instances
|
1019
1356
|
# of DateTime and ActiveSupport::TimeWithZone. You can still override that
|
1020
1357
|
# by passing the "value" option explicitly, e.g.
|
@@ -1042,7 +1379,7 @@ module ActionView
|
|
1042
1379
|
# Returns a text_field of type "time".
|
1043
1380
|
#
|
1044
1381
|
# The default value is generated by trying to call +strftime+ with "%T.%L"
|
1045
|
-
# on the
|
1382
|
+
# on the object's value. It is still possible to override that
|
1046
1383
|
# by passing the "value" option.
|
1047
1384
|
#
|
1048
1385
|
# === Options
|
@@ -1068,38 +1405,9 @@ module ActionView
|
|
1068
1405
|
Tags::TimeField.new(object_name, method, self, options).render
|
1069
1406
|
end
|
1070
1407
|
|
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
1408
|
# Returns a text_field of type "datetime-local".
|
1101
1409
|
#
|
1102
|
-
#
|
1410
|
+
# datetime_field("user", "born_on")
|
1103
1411
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" />
|
1104
1412
|
#
|
1105
1413
|
# The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T"
|
@@ -1107,25 +1415,27 @@ module ActionView
|
|
1107
1415
|
# of DateTime and ActiveSupport::TimeWithZone.
|
1108
1416
|
#
|
1109
1417
|
# @user.born_on = Date.new(1984, 1, 12)
|
1110
|
-
#
|
1418
|
+
# datetime_field("user", "born_on")
|
1111
1419
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" value="1984-01-12T00:00:00" />
|
1112
1420
|
#
|
1113
1421
|
# You can create values for the "min" and "max" attributes by passing
|
1114
1422
|
# instances of Date or Time to the options hash.
|
1115
1423
|
#
|
1116
|
-
#
|
1424
|
+
# datetime_field("user", "born_on", min: Date.today)
|
1117
1425
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" min="2014-05-20T00:00:00.000" />
|
1118
1426
|
#
|
1119
1427
|
# Alternatively, you can pass a String formatted as an ISO8601 datetime as
|
1120
1428
|
# the values for "min" and "max."
|
1121
1429
|
#
|
1122
|
-
#
|
1430
|
+
# datetime_field("user", "born_on", min: "2014-05-20T00:00:00")
|
1123
1431
|
# # => <input id="user_born_on" name="user[born_on]" type="datetime-local" min="2014-05-20T00:00:00.000" />
|
1124
1432
|
#
|
1125
|
-
def
|
1433
|
+
def datetime_field(object_name, method, options = {})
|
1126
1434
|
Tags::DatetimeLocalField.new(object_name, method, self, options).render
|
1127
1435
|
end
|
1128
1436
|
|
1437
|
+
alias datetime_local_field datetime_field
|
1438
|
+
|
1129
1439
|
# Returns a text_field of type "month".
|
1130
1440
|
#
|
1131
1441
|
# month_field("user", "born_on")
|
@@ -1195,6 +1505,34 @@ module ActionView
|
|
1195
1505
|
end
|
1196
1506
|
|
1197
1507
|
private
|
1508
|
+
def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: !form_with_generates_remote_forms,
|
1509
|
+
skip_enforcing_utf8: false, **options)
|
1510
|
+
html_options = options.slice(:id, :class, :multipart, :method, :data).merge(html)
|
1511
|
+
html_options[:method] ||= :patch if model.respond_to?(:persisted?) && model.persisted?
|
1512
|
+
html_options[:enforce_utf8] = !skip_enforcing_utf8
|
1513
|
+
|
1514
|
+
html_options[:enctype] = "multipart/form-data" if html_options.delete(:multipart)
|
1515
|
+
|
1516
|
+
# The following URL is unescaped, this is just a hash of options, and it is the
|
1517
|
+
# responsibility of the caller to escape all the values.
|
1518
|
+
html_options[:action] = url_for(url_for_options || {})
|
1519
|
+
html_options[:"accept-charset"] = "UTF-8"
|
1520
|
+
html_options[:"data-remote"] = true unless local
|
1521
|
+
|
1522
|
+
html_options[:authenticity_token] = options.delete(:authenticity_token)
|
1523
|
+
|
1524
|
+
if !local && html_options[:authenticity_token].blank?
|
1525
|
+
html_options[:authenticity_token] = embed_authenticity_token_in_remote_forms
|
1526
|
+
end
|
1527
|
+
|
1528
|
+
if html_options[:authenticity_token] == true
|
1529
|
+
# Include the default authenticity_token, which is only generated when it's set to nil,
|
1530
|
+
# but we needed the true value to override the default of no authenticity_token on data-remote.
|
1531
|
+
html_options[:authenticity_token] = nil
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
html_options.stringify_keys!
|
1535
|
+
end
|
1198
1536
|
|
1199
1537
|
def instantiate_builder(record_name, record_object, options)
|
1200
1538
|
case record_name
|
@@ -1203,7 +1541,7 @@ module ActionView
|
|
1203
1541
|
object_name = record_name
|
1204
1542
|
else
|
1205
1543
|
object = record_name
|
1206
|
-
object_name = model_name_from_record_or_class(object).param_key
|
1544
|
+
object_name = model_name_from_record_or_class(object).param_key if object
|
1207
1545
|
end
|
1208
1546
|
|
1209
1547
|
builder = options[:builder] || default_form_builder_class
|
@@ -1211,7 +1549,7 @@ module ActionView
|
|
1211
1549
|
end
|
1212
1550
|
|
1213
1551
|
def default_form_builder_class
|
1214
|
-
builder = ActionView::Base.default_form_builder
|
1552
|
+
builder = default_form_builder || ActionView::Base.default_form_builder
|
1215
1553
|
builder.respond_to?(:constantize) ? builder.constantize : builder
|
1216
1554
|
end
|
1217
1555
|
end
|
@@ -1269,7 +1607,7 @@ module ActionView
|
|
1269
1607
|
|
1270
1608
|
# The methods which wrap a form helper call.
|
1271
1609
|
class_attribute :field_helpers
|
1272
|
-
self.field_helpers = [:fields_for, :label, :text_field, :password_field,
|
1610
|
+
self.field_helpers = [:fields_for, :fields, :label, :text_field, :password_field,
|
1273
1611
|
:hidden_field, :file_field, :text_area, :check_box,
|
1274
1612
|
:radio_button, :color_field, :search_field,
|
1275
1613
|
:telephone_field, :phone_field, :date_field,
|
@@ -1291,7 +1629,7 @@ module ActionView
|
|
1291
1629
|
end
|
1292
1630
|
|
1293
1631
|
def self._to_partial_path
|
1294
|
-
@_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/,
|
1632
|
+
@_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/, "")
|
1295
1633
|
end
|
1296
1634
|
|
1297
1635
|
def to_partial_path
|
@@ -1305,19 +1643,23 @@ module ActionView
|
|
1305
1643
|
def initialize(object_name, object, template, options)
|
1306
1644
|
@nested_child_index = {}
|
1307
1645
|
@object_name, @object, @template, @options = object_name, object, template, options
|
1308
|
-
@default_options = @options ? @options.slice(:index, :namespace) : {}
|
1646
|
+
@default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids, :allow_method_names_outside_object) : {}
|
1647
|
+
|
1648
|
+
convert_to_legacy_options(@options)
|
1649
|
+
|
1309
1650
|
if @object_name.to_s.match(/\[\]$/)
|
1310
|
-
if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")
|
1651
|
+
if (object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")) && object.respond_to?(:to_param)
|
1311
1652
|
@auto_index = object.to_param
|
1312
1653
|
else
|
1313
1654
|
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
|
1314
1655
|
end
|
1315
1656
|
end
|
1657
|
+
|
1316
1658
|
@multipart = nil
|
1317
1659
|
@index = options[:index] || options[:child_index]
|
1318
1660
|
end
|
1319
1661
|
|
1320
|
-
(field_helpers - [:label, :check_box, :radio_button, :fields_for, :hidden_field, :file_field]).each do |selector|
|
1662
|
+
(field_helpers - [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]).each do |selector|
|
1321
1663
|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
1322
1664
|
def #{selector}(method, options = {}) # def text_field(method, options = {})
|
1323
1665
|
@template.send( # @template.send(
|
@@ -1586,19 +1928,37 @@ module ActionView
|
|
1586
1928
|
record_name = model_name_from_record_or_class(record_object).param_key
|
1587
1929
|
end
|
1588
1930
|
|
1931
|
+
object_name = @object_name
|
1589
1932
|
index = if options.has_key?(:index)
|
1590
1933
|
options[:index]
|
1591
1934
|
elsif defined?(@auto_index)
|
1592
|
-
|
1935
|
+
object_name = object_name.to_s.sub(/\[\]$/, "")
|
1593
1936
|
@auto_index
|
1594
1937
|
end
|
1595
1938
|
|
1596
|
-
record_name =
|
1939
|
+
record_name = if index
|
1940
|
+
"#{object_name}[#{index}][#{record_name}]"
|
1941
|
+
elsif record_name.to_s.end_with?("[]")
|
1942
|
+
record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]")
|
1943
|
+
"#{object_name}#{record_name}"
|
1944
|
+
else
|
1945
|
+
"#{object_name}[#{record_name}]"
|
1946
|
+
end
|
1597
1947
|
fields_options[:child_index] = index
|
1598
1948
|
|
1599
1949
|
@template.fields_for(record_name, record_object, fields_options, &block)
|
1600
1950
|
end
|
1601
1951
|
|
1952
|
+
# See the docs for the <tt>ActionView::FormHelper.fields</tt> helper method.
|
1953
|
+
def fields(scope = nil, model: nil, **options, &block)
|
1954
|
+
options[:allow_method_names_outside_object] = true
|
1955
|
+
options[:skip_default_ids] = true
|
1956
|
+
|
1957
|
+
convert_to_legacy_options(options)
|
1958
|
+
|
1959
|
+
fields_for(scope || model, model, **options, &block)
|
1960
|
+
end
|
1961
|
+
|
1602
1962
|
# Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
|
1603
1963
|
# assigned to the template (identified by +object+). The text of label will default to the attribute name unless a translation
|
1604
1964
|
# is found in the current I18n locale (through helpers.label.<modelname>.<attribute>) or you specify it explicitly.
|
@@ -1607,7 +1967,7 @@ module ActionView
|
|
1607
1967
|
# target labels for radio_button tags (where the value is used in the ID of the input tag).
|
1608
1968
|
#
|
1609
1969
|
# ==== Examples
|
1610
|
-
# label(:
|
1970
|
+
# label(:title)
|
1611
1971
|
# # => <label for="post_title">Title</label>
|
1612
1972
|
#
|
1613
1973
|
# You can localize your labels based on model and attribute names.
|
@@ -1620,7 +1980,7 @@ module ActionView
|
|
1620
1980
|
#
|
1621
1981
|
# Which then will result in
|
1622
1982
|
#
|
1623
|
-
# label(:
|
1983
|
+
# label(:body)
|
1624
1984
|
# # => <label for="post_body">Write your entire text here</label>
|
1625
1985
|
#
|
1626
1986
|
# Localization can also be based purely on the translation of the attribute-name
|
@@ -1631,21 +1991,22 @@ module ActionView
|
|
1631
1991
|
# post:
|
1632
1992
|
# cost: "Total cost"
|
1633
1993
|
#
|
1634
|
-
# label(:
|
1994
|
+
# label(:cost)
|
1635
1995
|
# # => <label for="post_cost">Total cost</label>
|
1636
1996
|
#
|
1637
|
-
# label(:
|
1997
|
+
# label(:title, "A short title")
|
1638
1998
|
# # => <label for="post_title">A short title</label>
|
1639
1999
|
#
|
1640
|
-
# label(:
|
2000
|
+
# label(:title, "A short title", class: "title_label")
|
1641
2001
|
# # => <label for="post_title" class="title_label">A short title</label>
|
1642
2002
|
#
|
1643
|
-
# label(:
|
2003
|
+
# label(:privacy, "Public Post", value: "public")
|
1644
2004
|
# # => <label for="post_privacy_public">Public Post</label>
|
1645
2005
|
#
|
1646
|
-
# label(:
|
1647
|
-
# 'Accept <a href="/terms">Terms</a>.'
|
2006
|
+
# label(:terms) do
|
2007
|
+
# raw('Accept <a href="/terms">Terms</a>.')
|
1648
2008
|
# end
|
2009
|
+
# # => <label for="post_terms">Accept <a href="/terms">Terms</a>.</label>
|
1649
2010
|
def label(method, text = nil, options = {}, &block)
|
1650
2011
|
@template.label(@object_name, method, text, objectify_options(options), &block)
|
1651
2012
|
end
|
@@ -1694,16 +2055,17 @@ module ActionView
|
|
1694
2055
|
# hashes instead of arrays.
|
1695
2056
|
#
|
1696
2057
|
# # Let's say that @post.validated? is 1:
|
1697
|
-
# check_box("
|
2058
|
+
# check_box("validated")
|
1698
2059
|
# # => <input name="post[validated]" type="hidden" value="0" />
|
1699
2060
|
# # <input checked="checked" type="checkbox" id="post_validated" name="post[validated]" value="1" />
|
1700
2061
|
#
|
1701
2062
|
# # Let's say that @puppy.gooddog is "no":
|
1702
|
-
# check_box("
|
2063
|
+
# check_box("gooddog", {}, "yes", "no")
|
1703
2064
|
# # => <input name="puppy[gooddog]" type="hidden" value="no" />
|
1704
2065
|
# # <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
|
1705
2066
|
#
|
1706
|
-
#
|
2067
|
+
# # Let's say that @eula.accepted is "no":
|
2068
|
+
# check_box("accepted", { class: 'eula_check' }, "yes", "no")
|
1707
2069
|
# # => <input name="eula[accepted]" type="hidden" value="no" />
|
1708
2070
|
# # <input type="checkbox" class="eula_check" id="eula_accepted" name="eula[accepted]" value="yes" />
|
1709
2071
|
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
@@ -1718,13 +2080,14 @@ module ActionView
|
|
1718
2080
|
# +options+ hash. You may pass HTML options there as well.
|
1719
2081
|
#
|
1720
2082
|
# # Let's say that @post.category returns "rails":
|
1721
|
-
# radio_button("
|
1722
|
-
# radio_button("
|
2083
|
+
# radio_button("category", "rails")
|
2084
|
+
# radio_button("category", "java")
|
1723
2085
|
# # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" />
|
1724
2086
|
# # <input type="radio" id="post_category_java" name="post[category]" value="java" />
|
1725
2087
|
#
|
1726
|
-
#
|
1727
|
-
# radio_button("
|
2088
|
+
# # Let's say that @user.receive_newsletter returns "no":
|
2089
|
+
# radio_button("receive_newsletter", "yes")
|
2090
|
+
# radio_button("receive_newsletter", "no")
|
1728
2091
|
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
|
1729
2092
|
# # <input type="radio" id="user_receive_newsletter_no" name="user[receive_newsletter]" value="no" checked="checked" />
|
1730
2093
|
def radio_button(method, tag_value, options = {})
|
@@ -1737,14 +2100,17 @@ module ActionView
|
|
1737
2100
|
# shown.
|
1738
2101
|
#
|
1739
2102
|
# ==== Examples
|
1740
|
-
#
|
1741
|
-
#
|
2103
|
+
# # Let's say that @signup.pass_confirm returns true:
|
2104
|
+
# hidden_field(:pass_confirm)
|
2105
|
+
# # => <input type="hidden" id="signup_pass_confirm" name="signup[pass_confirm]" value="true" />
|
1742
2106
|
#
|
1743
|
-
#
|
1744
|
-
#
|
2107
|
+
# # Let's say that @post.tag_list returns "blog, ruby":
|
2108
|
+
# hidden_field(:tag_list)
|
2109
|
+
# # => <input type="hidden" id="post_tag_list" name="post[tag_list]" value="blog, ruby" />
|
1745
2110
|
#
|
1746
|
-
#
|
1747
|
-
#
|
2111
|
+
# # Let's say that @user.token returns "abcde":
|
2112
|
+
# hidden_field(:token)
|
2113
|
+
# # => <input type="hidden" id="user_token" name="user[token]" value="abcde" />
|
1748
2114
|
#
|
1749
2115
|
def hidden_field(method, options = {})
|
1750
2116
|
@emitted_hidden_id = true if method == :id
|
@@ -1765,19 +2131,24 @@ module ActionView
|
|
1765
2131
|
# * <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
2132
|
#
|
1767
2133
|
# ==== Examples
|
1768
|
-
#
|
2134
|
+
# # Let's say that @user has avatar:
|
2135
|
+
# file_field(:avatar)
|
1769
2136
|
# # => <input type="file" id="user_avatar" name="user[avatar]" />
|
1770
2137
|
#
|
1771
|
-
#
|
1772
|
-
#
|
2138
|
+
# # Let's say that @post has image:
|
2139
|
+
# file_field(:image, :multiple => true)
|
2140
|
+
# # => <input type="file" id="post_image" name="post[image][]" multiple="multiple" />
|
1773
2141
|
#
|
1774
|
-
#
|
2142
|
+
# # Let's say that @post has attached:
|
2143
|
+
# file_field(:attached, accept: 'text/html')
|
1775
2144
|
# # => <input accept="text/html" type="file" id="post_attached" name="post[attached]" />
|
1776
2145
|
#
|
1777
|
-
#
|
2146
|
+
# # Let's say that @post has image:
|
2147
|
+
# file_field(:image, accept: 'image/png,image/gif,image/jpeg')
|
1778
2148
|
# # => <input type="file" id="post_image" name="post[image]" accept="image/png,image/gif,image/jpeg" />
|
1779
2149
|
#
|
1780
|
-
#
|
2150
|
+
# # Let's say that @attachment has file:
|
2151
|
+
# file_field(:file, class: 'file_input')
|
1781
2152
|
# # => <input type="file" id="attachment_file" name="attachment[file]" class="file_input" />
|
1782
2153
|
def file_field(method, options = {})
|
1783
2154
|
self.multipart = true
|
@@ -1811,7 +2182,7 @@ module ActionView
|
|
1811
2182
|
# post:
|
1812
2183
|
# create: "Add %{model}"
|
1813
2184
|
#
|
1814
|
-
def submit(value=nil, options={})
|
2185
|
+
def submit(value = nil, options = {})
|
1815
2186
|
value, options = nil, value if value.is_a?(Hash)
|
1816
2187
|
value ||= submit_default_value
|
1817
2188
|
@template.submit_tag(value, options)
|
@@ -1845,7 +2216,7 @@ module ActionView
|
|
1845
2216
|
# create: "Add %{model}"
|
1846
2217
|
#
|
1847
2218
|
# ==== Examples
|
1848
|
-
# button("Create
|
2219
|
+
# button("Create post")
|
1849
2220
|
# # => <button name='button' type='submit'>Create post</button>
|
1850
2221
|
#
|
1851
2222
|
# button do
|
@@ -1906,7 +2277,11 @@ module ActionView
|
|
1906
2277
|
explicit_child_index = options[:child_index]
|
1907
2278
|
output = ActiveSupport::SafeBuffer.new
|
1908
2279
|
association.each do |child|
|
1909
|
-
|
2280
|
+
if explicit_child_index
|
2281
|
+
options[:child_index] = explicit_child_index.call if explicit_child_index.respond_to?(:call)
|
2282
|
+
else
|
2283
|
+
options[:child_index] = nested_child_index(name)
|
2284
|
+
end
|
1910
2285
|
output << fields_for_nested_model("#{name}[#{options[:child_index]}]", child, options, block)
|
1911
2286
|
end
|
1912
2287
|
output
|
@@ -1932,6 +2307,12 @@ module ActionView
|
|
1932
2307
|
@nested_child_index[name] ||= -1
|
1933
2308
|
@nested_child_index[name] += 1
|
1934
2309
|
end
|
2310
|
+
|
2311
|
+
def convert_to_legacy_options(options)
|
2312
|
+
if options.key?(:skip_id)
|
2313
|
+
options[:include_id] = !options.delete(:skip_id)
|
2314
|
+
end
|
2315
|
+
end
|
1935
2316
|
end
|
1936
2317
|
end
|
1937
2318
|
|