diff options
-rw-r--r-- | actionpack/lib/action_view/helpers/form_helper.rb | 10 | ||||
-rw-r--r-- | actionpack/test/template/form_helper_test.rb | 92 |
2 files changed, 98 insertions, 4 deletions
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 8ecec87b10..6d6d623938 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -926,6 +926,7 @@ module ActionView attr_accessor :object_name, :object, :options def initialize(object_name, object, template, options, proc) + @nested_child_index = {} @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc @default_options = @options ? @options.slice(:index) : {} if @object_name.to_s.match(/\[\]$/) @@ -1028,7 +1029,7 @@ module ActionView explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash) children.map do |child| - fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index}]", child, args, block) + fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block) end.join else fields_for_nested_model(name, explicit_object || association, args, block) @@ -1046,9 +1047,9 @@ module ActionView end end - def nested_child_index - @nested_child_index ||= -1 - @nested_child_index += 1 + def nested_child_index(name) + @nested_child_index[name] ||= -1 + @nested_child_index[name] += 1 end end end @@ -1056,5 +1057,6 @@ module ActionView class << Base attr_accessor :default_form_builder end + Base.default_form_builder = ::ActionView::Helpers::FormBuilder end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 56cdf6df9a..515f73c339 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -21,6 +21,9 @@ silence_warnings do attr_accessor :comments def comments_attributes=(attributes); end + + attr_accessor :tags + def tags_attributes=(attributes); end end class Comment @@ -33,6 +36,50 @@ silence_warnings do def name @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + + end + + class Tag + attr_reader :id + attr_reader :post_id + def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def save; @id = 1; @post_id = 1 end + def new_record?; @id.nil? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + + end + + class CommentRelevance + attr_reader :id + attr_reader :comment_id + def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end + def save; @id = 1; @comment_id = 1 end + def new_record?; @id.nil? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + end + + class TagRelevance + attr_reader :id + attr_reader :tag_id + def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end + def save; @id = 1; @tag_id = 1 end + def new_record?; @id.nil? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end end class Author < Comment @@ -740,6 +787,51 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal expected, output_buffer end + def test_nested_fields_uses_unique_indices_for_different_collection_associations + @post.comments = [Comment.new(321)] + @post.tags = [Tag.new(123), Tag.new(456)] + @post.comments[0].relevances = [] + @post.tags[0].relevances = [] + @post.tags[1].relevances = [] + form_for(:post, @post) do |f| + f.fields_for(:comments, @post.comments[0]) do |cf| + concat cf.text_field(:name) + cf.fields_for(:relevances, CommentRelevance.new(314)) do |crf| + concat crf.text_field(:value) + end + end + f.fields_for(:tags, @post.tags[0]) do |tf| + concat tf.text_field(:value) + tf.fields_for(:relevances, TagRelevance.new(3141)) do |trf| + concat trf.text_field(:value) + end + end + f.fields_for('tags', @post.tags[1]) do |tf| + concat tf.text_field(:value) + tf.fields_for(:relevances, TagRelevance.new(31415)) do |trf| + concat trf.text_field(:value) + end + end + end + + expected = '<form action="http://www.example.com" method="post">' + + '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' + + '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" />' + + '<input id="post_comments_attributes_0_relevances_attributes_0_id" name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' + + '<input id="post_comments_attributes_0_relevances_attributes_0_value" name="post[comments_attributes][0][relevances_attributes][0][value]" size="30" type="text" value="commentrelevance #314" />' + + '<input id="post_tags_attributes_0_id" name="post[tags_attributes][0][id]" type="hidden" value="123" />' + + '<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" size="30" type="text" value="tag #123" />' + + '<input id="post_tags_attributes_0_relevances_attributes_0_id" name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' + + '<input id="post_tags_attributes_0_relevances_attributes_0_value" name="post[tags_attributes][0][relevances_attributes][0][value]" size="30" type="text" value="tagrelevance #3141" />' + + '<input id="post_tags_attributes_1_id" name="post[tags_attributes][1][id]" type="hidden" value="456" />' + + '<input id="post_tags_attributes_1_value" name="post[tags_attributes][1][value]" size="30" type="text" value="tag #456" />' + + '<input id="post_tags_attributes_1_relevances_attributes_0_id" name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' + + '<input id="post_tags_attributes_1_relevances_attributes_0_value" name="post[tags_attributes][1][relevances_attributes][0][value]" size="30" type="text" value="tagrelevance #31415" />' + + '</form>' + + assert_dom_equal expected, output_buffer + end + def test_fields_for fields_for(:post, @post) do |f| concat f.text_field(:title) |