Skip to content

Commit 269f672

Browse files
authored
Merge pull request rails#43421 from seanpdoyle/action-view-unify-form-implementation
Implement `form_for` by delegating to `form_with`
2 parents 59eb7ed + 4997cc7 commit 269f672

File tree

2 files changed

+31
-57
lines changed

2 files changed

+31
-57
lines changed

actionview/lib/action_view/helpers/form_helper.rb

Lines changed: 30 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -432,52 +432,45 @@ module FormHelper
432432
# <% end %>
433433
def form_for(record, options = {}, &block)
434434
raise ArgumentError, "Missing block" unless block_given?
435-
html_options = options[:html] ||= {}
436435

437436
case record
438437
when String, Symbol
438+
model = nil
439439
object_name = record
440-
object = nil
441440
else
441+
model = record
442442
object = _object_for_form_builder(record)
443443
raise ArgumentError, "First argument in form cannot contain nil or be empty" unless object
444444
object_name = options[:as] || model_name_from_record_or_class(object).param_key
445-
apply_form_for_options!(record, object, options)
445+
apply_form_for_options!(object, options)
446446
end
447447

448-
html_options[:data] = options.delete(:data) if options.has_key?(:data)
449-
html_options[:remote] = options.delete(:remote) if options.has_key?(:remote)
450-
html_options[:method] = options.delete(:method) if options.has_key?(:method)
451-
html_options[:enforce_utf8] = options.delete(:enforce_utf8) if options.has_key?(:enforce_utf8)
452-
html_options[:authenticity_token] = options.delete(:authenticity_token)
448+
remote = options.delete(:remote)
453449

454-
builder = instantiate_builder(object_name, object, options)
455-
output = capture(builder, &block)
456-
html_options[:multipart] ||= builder.multipart?
450+
if remote && !embed_authenticity_token_in_remote_forms && options[:authenticity_token].blank?
451+
options[:authenticity_token] = false
452+
end
453+
454+
options[:model] = model
455+
options[:scope] = object_name
456+
options[:local] = !remote
457+
options[:skip_default_ids] = false
458+
options[:allow_method_names_outside_object] = options.fetch(:allow_method_names_outside_object, false)
457459

458-
html_options = html_options_for_form(options.fetch(:url, {}), html_options)
459-
form_tag_with_body(html_options, output)
460+
form_with(**options, &block)
460461
end
461462

462-
def apply_form_for_options!(record, object, options) # :nodoc:
463+
def apply_form_for_options!(object, options) # :nodoc:
463464
object = convert_to_model(object)
464465

465466
as = options[:as]
466467
namespace = options[:namespace]
467-
action, method = object.respond_to?(:persisted?) && object.persisted? ? [:edit, :patch] : [:new, :post]
468+
action = object.respond_to?(:persisted?) && object.persisted? ? :edit : :new
469+
options[:html] ||= {}
468470
options[:html].reverse_merge!(
469471
class: as ? "#{action}_#{as}" : dom_class(object, action),
470472
id: (as ? [namespace, action, as] : [namespace, dom_id(object, action)]).compact.join("_").presence,
471-
method: method
472473
)
473-
474-
if options[:url] != false
475-
options[:url] ||= if options.key?(:format)
476-
polymorphic_path(record, format: options.delete(:format))
477-
else
478-
polymorphic_path(record, {})
479-
end
480-
end
481474
end
482475
private :apply_form_for_options!
483476

@@ -757,8 +750,7 @@ def apply_form_for_options!(record, object, options) # :nodoc:
757750
# form_with(**options.merge(builder: LabellingFormBuilder), &block)
758751
# end
759752
def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
760-
options[:allow_method_names_outside_object] = true
761-
options[:skip_default_ids] = !form_with_generates_ids
753+
options = { allow_method_names_outside_object: true, skip_default_ids: !form_with_generates_ids }.merge!(options)
762754

763755
if model
764756
if url != false
@@ -1024,8 +1016,9 @@ def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
10241016
# hidden field is not needed and you can pass <tt>include_id: false</tt>
10251017
# to prevent fields_for from rendering it automatically.
10261018
def fields_for(record_name, record_object = nil, options = {}, &block)
1027-
builder = instantiate_builder(record_name, record_object, options)
1028-
capture(builder, &block)
1019+
options = { model: record_object, allow_method_names_outside_object: false, skip_default_ids: false }.merge!(options)
1020+
1021+
fields(record_name, **options, &block)
10291022
end
10301023

10311024
# Scopes input fields with either an explicit scope or model.
@@ -1074,8 +1067,7 @@ def fields_for(record_name, record_object = nil, options = {}, &block)
10741067
# to work with an object as a base, like
10751068
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
10761069
def fields(scope = nil, model: nil, **options, &block)
1077-
options[:allow_method_names_outside_object] = true
1078-
options[:skip_default_ids] = !form_with_generates_ids
1070+
options = { allow_method_names_outside_object: true, skip_default_ids: !form_with_generates_ids }.merge!(options)
10791071

10801072
if model
10811073
model = _object_for_form_builder(model)
@@ -1575,35 +1567,17 @@ def _object_for_form_builder(object) # :nodoc:
15751567
private
15761568
def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: !form_with_generates_remote_forms,
15771569
skip_enforcing_utf8: nil, **options)
1578-
html_options = options.slice(:id, :class, :multipart, :method, :data).merge(html)
1570+
html_options = options.slice(:id, :class, :multipart, :method, :data, :authenticity_token).merge!(html)
1571+
html_options[:remote] = html.delete(:remote) || !local
15791572
html_options[:method] ||= :patch if model.respond_to?(:persisted?) && model.persisted?
1580-
html_options[:enforce_utf8] = !skip_enforcing_utf8 unless skip_enforcing_utf8.nil?
1581-
1582-
html_options[:enctype] = "multipart/form-data" if html_options.delete(:multipart)
1583-
1584-
# The following URL is unescaped, this is just a hash of options, and it is the
1585-
# responsibility of the caller to escape all the values.
1586-
if url_for_options == false || html_options[:action] == false
1587-
html_options.delete(:action)
1573+
if skip_enforcing_utf8.nil?
1574+
if options.key?(:enforce_utf8)
1575+
html_options[:enforce_utf8] = options[:enforce_utf8]
1576+
end
15881577
else
1589-
html_options[:action] = url_for(url_for_options || {})
1578+
html_options[:enforce_utf8] = !skip_enforcing_utf8
15901579
end
1591-
html_options[:"accept-charset"] = "UTF-8"
1592-
html_options[:"data-remote"] = true unless local
1593-
1594-
html_options[:authenticity_token] = options.delete(:authenticity_token)
1595-
1596-
if !local && html_options[:authenticity_token].blank?
1597-
html_options[:authenticity_token] = embed_authenticity_token_in_remote_forms
1598-
end
1599-
1600-
if html_options[:authenticity_token] == true
1601-
# Include the default authenticity_token, which is only generated when it's set to nil,
1602-
# but we needed the true value to override the default of no authenticity_token on data-remote.
1603-
html_options[:authenticity_token] = nil
1604-
end
1605-
1606-
html_options.stringify_keys!
1580+
html_options_for_form(url_for_options.nil? ? {} : url_for_options, html_options)
16071581
end
16081582

16091583
def instantiate_builder(record_name, record_object, options)

actionview/lib/action_view/helpers/form_tag_helper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ def html_options_for_form(url_for_options, options)
914914
html_options["data-remote"] = true if html_options.delete("remote")
915915

916916
if html_options["data-remote"] &&
917-
!embed_authenticity_token_in_remote_forms &&
917+
embed_authenticity_token_in_remote_forms == false &&
918918
html_options["authenticity_token"].blank?
919919
# The authenticity token is taken from the meta tag in this case
920920
html_options["authenticity_token"] = false

0 commit comments

Comments
 (0)