Skip to content

Commit

Permalink
Merge PR #43409
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelfranca committed Nov 15, 2021
2 parents 27d24e9 + 37081bf commit 876d2ff
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 9 deletions.
12 changes: 12 additions & 0 deletions actionview/CHANGELOG.md
@@ -1,3 +1,15 @@
* Introduce the `field_name` view helper, along with the
`FormBuilder#field_name` counterpart:

```ruby
form_for @post do |f|
f.field_tag :tag, name: f.field_name(:tag, multiple: true)
# => <input type="text" name="post[tag][]">
end
```

*Sean Doyle*

* Execute the `ActionView::Base.field_error_proc` within the context of the
`ActionView::Base` instance:

Expand Down
22 changes: 22 additions & 0 deletions actionview/lib/action_view/helpers/form_helper.rb
Expand Up @@ -1769,6 +1769,28 @@ def field_id(method, *suffixes, index: @index)
@template.field_id(@object_name, method, *suffixes, index: index)
end

# Generate an HTML <tt>name</tt> attribute value for the given name and
# field combination
#
# Return the value generated by the <tt>FormBuilder</tt> for the given
# attribute name.
#
# <%= form_for @post do |f| %>
# <%= f.text_field :title, name: f.field_name(:title, :subtitle) %>
# <%# => <input type="text" name="post[title][subtitle]">
# <% end %>
#
# <%= form_for @post do |f| %>
# <%= f.field_tag :tag, name: f.field_name(:tag, multiple: true) %>
# <%# => <input type="text" name="post[tag][]">
# <% end %>
#
def field_name(method, *methods, multiple: false, index: @index)
object_name = @options.fetch(:as) { @object_name }

@template.field_name(object_name, method, *methods, index: index, multiple: multiple)
end

##
# :method: text_field
#
Expand Down
26 changes: 26 additions & 0 deletions actionview/lib/action_view/helpers/form_tag_helper.rb
Expand Up @@ -117,6 +117,32 @@ def field_id(object_name, method_name, *suffixes, index: nil)
end
end

# Generate an HTML <tt>name</tt> attribute value for the given name and
# field combination
#
# Return the value generated by the <tt>FormBuilder</tt> for the given
# attribute name.
#
# <%= text_field_tag :post, :title, name: field_name(:post, :title, :subtitle) %>
# <%# => <input type="text" name="post[title][subtitle]">
#
# <%= text_field_tag :post, :tag, name: field_name(:post, :tag, multiple: true) %>
# <%# => <input type="text" name="post[tag][]">
#
def field_name(object_name, method_name, *method_names, multiple: false, index: nil)
names = method_names.map! { |name| "[#{name}]" }.join

# a little duplication to construct fewer strings
case
when object_name.empty?
"#{method_name}#{names}#{multiple ? "[]" : ""}"
when index
"#{object_name}[#{index}][#{method_name}]#{names}#{multiple ? "[]" : ""}"
else
"#{object_name}[#{method_name}]#{names}#{multiple ? "[]" : ""}"
end
end

# Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
# choice selection box.
#
Expand Down
10 changes: 1 addition & 9 deletions actionview/lib/action_view/helpers/tags/base.rb
Expand Up @@ -105,15 +105,7 @@ def add_default_name_and_id(options)
end

def tag_name(multiple = false, index = nil)
# a little duplication to construct fewer strings
case
when @object_name.empty?
"#{sanitized_method_name}#{multiple ? "[]" : ""}"
when index
"#{@object_name}[#{index}][#{sanitized_method_name}]#{multiple ? "[]" : ""}"
else
"#{@object_name}[#{sanitized_method_name}]#{multiple ? "[]" : ""}"
end
@template_object.field_name(@object_name, sanitized_method_name, multiple: multiple, index: index)
end

def tag_id(index = nil)
Expand Down
120 changes: 120 additions & 0 deletions actionview/test/template/form_helper_test.rb
Expand Up @@ -1677,6 +1677,126 @@ def test_form_for_field_id_with_index
assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_with_blank_as
form_for(Post.new, as: "") do |form|
concat form.text_field(:title, name: form.field_name(:title))
end

expected = whole_form("/posts", "new_", "new_") do
%(<input id="title" name="title" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_with_blank_as_and_multiple
form_for(Post.new, as: "") do |form|
concat form.text_field(:title, name: form.field_name(:title, multiple: true))
end

expected = whole_form("/posts", "new_", "new_") do
%(<input id="title" name="title[]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_without_method_names_or_multiple_or_index
form_for(Post.new) do |form|
concat form.text_field(:title, name: form.field_name(:title))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_title" name="post[title]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_without_method_names_and_multiple
form_for(Post.new) do |form|
concat form.text_field(:title, name: form.field_name(:title, multiple: true))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_title" name="post[title][]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_without_method_names_and_index
form_for(Post.new, index: 1) do |form|
concat form.text_field(:title, name: form.field_name(:title))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_1_title" name="post[1][title]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_without_method_names_and_index_and_multiple
form_for(Post.new, index: 1) do |form|
concat form.text_field(:title, name: form.field_name(:title, multiple: true))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_1_title" name="post[1][title][]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_with_method_names
form_for(Post.new) do |form|
concat form.text_field(:title, name: form.field_name(:title, :subtitle))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_title" name="post[title][subtitle]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_with_method_names_and_index
form_for(Post.new, index: 1) do |form|
concat form.text_field(:title, name: form.field_name(:title, :subtitle))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_1_title" name="post[1][title][subtitle]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_with_method_names_and_multiple
form_for(Post.new) do |form|
concat form.text_field(:title, name: form.field_name(:title, :subtitle, multiple: true))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_title" name="post[title][subtitle][]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_field_name_with_method_names_and_multiple_and_index
form_for(Post.new, index: 1) do |form|
concat form.text_field(:title, name: form.field_name(:title, :subtitle, multiple: true))
end

expected = whole_form("/posts", "new_post", "new_post") do
%(<input id="post_1_title" name="post[1][title][subtitle][]" type="text">)
end

assert_dom_equal expected, output_buffer
end

def test_form_for_with_collection_radio_buttons
post = Post.new
def post.active; false; end
Expand Down
60 changes: 60 additions & 0 deletions actionview/test/template/form_tag_helper_test.rb
Expand Up @@ -225,6 +225,66 @@ def test_field_id_with_nested_object_name
assert_equal "post_author_name", value
end

def test_field_name_without_object_name
value = field_name("", :title)

assert_equal "title", value
end

def test_field_name_without_object_name_and_multiple
value = field_name("", :title, multiple: true)

assert_equal "title[]", value
end

def test_field_name_without_method_names_or_multiple_or_index
value = field_name(:post, :title)

assert_equal "post[title]", value
end

def test_field_name_without_method_names_and_multiple
value = field_name(:post, :title, multiple: true)

assert_equal "post[title][]", value
end

def test_field_name_without_method_names_and_index
value = field_name(:post, :title, index: 1)

assert_equal "post[1][title]", value
end

def test_field_name_without_method_names_and_index_and_multiple
value = field_name(:post, :title, index: 1, multiple: true)

assert_equal "post[1][title][]", value
end

def test_field_name_with_method_names
value = field_name(:post, :title, :subtitle)

assert_equal "post[title][subtitle]", value
end

def test_field_name_with_method_names_and_index
value = field_name(:post, :title, :subtitle, index: 1)

assert_equal "post[1][title][subtitle]", value
end

def test_field_name_with_method_names_and_multiple
value = field_name(:post, :title, :subtitle, multiple: true)

assert_equal "post[title][subtitle][]", value
end

def test_field_name_with_method_names_and_multiple_and_index
value = field_name(:post, :title, :subtitle, index: 1, multiple: true)

assert_equal "post[1][title][subtitle][]", value
end

def test_hidden_field_tag
actual = hidden_field_tag "id", 3
expected = %(<input id="id" name="id" type="hidden" value="3" autocomplete="off" />)
Expand Down

0 comments on commit 876d2ff

Please sign in to comment.