Permalink
Browse files

support for nested attributes with dynamic number of elements

  • Loading branch information...
1 parent c9d1d20 commit d11b382e6df0ffa0f2a1bf2856c0e75bc9889539 @pkmiec pkmiec committed Oct 31, 2011
@@ -60,7 +60,11 @@ $.fn.isValid = (validators) ->
if obj.is('form')
validateForm(obj, validators)
else
- validateElement(obj, validators[@[0].name])
+ validateElement(obj, validatorsFor(@[0].name, validators))
+
+validatorsFor = (name, validators) ->
+ name = name.replace(/_attributes\]\[\d+\]/g,"_attributes][]")
+ validators[name]
validateForm = (form, validators) ->
form.trigger('form:validate:before')
@@ -81,7 +81,8 @@ def apply_client_side_validators(method, options = {})
if @options[:validate] && options[:validate] != false && validators = filter_validators(method, options[:validate])
options.merge!("data-validate" => true)
name = options[:name] || "#{@object_name}[#{method}]"
-
+ child_index = @options[:child_index] ? "(\\d+|#{Regexp.escape(@options[:child_index])})" : "\\d+"
+ name = name.gsub(/_attributes\]\[#{child_index}\]/, '_attributes][]')
@options[:validators].merge!("#{name}#{options[:multiple] ? "[]" : nil}" => validators)
end
end
@@ -208,6 +208,37 @@ def test_nested_fields_for_inherit_validation_settings
assert_equal expected, output_buffer
end
+ def test_nested_fields_for_with_nested_attributes
+ form_for(@post, :validate => true) do |f|
+ concat f.fields_for(:comments, [@comment]) { |c|
+ concat c.text_field(:title)
+ }
+ end
+
+ validators = {'post[comments_attributes][][title]' => {:presence => {:message => "can't be blank"}}}
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
+ %{<input data-validate="true" id="post_comments_attributes_0_title" name="post[comments_attributes][0][title]" size="30" type="text" />}
+ end
+
+ assert_equal expected, output_buffer
+ end
+
+ def test_nested_fields_for_with_nested_attributes_with_child_index
+ form_for(@post, :validate => true) do |f|
+ concat f.fields_for(:comments, [Comment.new], :child_index => '__INDEX__') { |c|
+ concat c.text_field(:title)
+ }
+ end
+
+ validators = {'post[comments_attributes][][title]' => {:presence => {:message => "can't be blank"}}}
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
+ %{<input data-validate="true" id="post_comments_attributes___INDEX___title" name="post[comments_attributes][__INDEX__][title]" size="30" type="text" />}
+ end
+
+ assert_equal expected, output_buffer
+ end
+
+
def test_nested_fields_for_dont_overwrite_validation_with_inheritance
form_for(@post, :validate => true) do |f|
concat f.fields_for(:comment, @comment, :validate => false) { |c|
@@ -8,7 +8,8 @@ module('Validate Element', {
'user[name]':{"presence":{"message": "must be present"}, "format":{"message":"is invalid","with":/\d+/}},
'user[password]':{"confirmation":{"message": "must match confirmation"}},
'user[agree]':{"acceptance": {"message": "must be accepted"}},
- 'user[email]':{"uniqueness":{"message": "must be unique"},"presence":{"message": "must be present"}}
+ 'user[email]':{"uniqueness":{"message": "must be unique"},"presence":{"message": "must be present"}},
+ 'user[phone_numbers_attributes][][number]':{"presence":{"message": "must be present"}}
}
}
@@ -54,7 +55,20 @@ module('Validate Element', {
'data-validate': 'true',
type: 'text'
}))
-
+ .append($('<label for="user_phone_numbers_attributes_0_number">Phone Number</label>'))
+ .append($('<input />', {
+ name: 'user[phone_numbers_attributes][0][number]',
+ id: 'user_phone_numbers_attributes_0_number',
+ 'data-validate': 'true',
+ type: 'text'
+ }))
+ .append($('<label for="user_phone_numbers_attributes_1_number">Phone Number</label>'))
+ .append($('<input />', {
+ name: 'user[phone_numbers_attributes][1][number]',
+ id: 'user_phone_numbers_attributes_1_number',
+ 'data-validate': 'true',
+ type: 'text'
+ }))
$('form#new_user').validate();
}
});
@@ -88,6 +102,22 @@ test('Validate when focusout on confirmation', function() {
ok(label.parent().hasClass('field_with_errors'));
});
+test('Validate nested attributes', function() {
+ var form = $('form#new_user'), input, label;
+
+ input = form.find('input#user_phone_numbers_attributes_1_number');
+ label = $('label[for="user_phone_numbers_attributes_1_number"]');
+ input.trigger('focusout');
+ ok(input.parent().hasClass('field_with_errors'));
+ ok(label.parent().hasClass('field_with_errors'));
+
+ input = form.find('input#user_phone_numbers_attributes_0_number');
+ label = $('label[for="user_phone_numbers_attributes_0_number"]');
+ input.trigger('focusout');
+ ok(input.parent().hasClass('field_with_errors'));
+ ok(label.parent().hasClass('field_with_errors'));
+});
+
test('Validate when keyup on confirmation', function() {
var form = $('form#new_user'), password = form.find('input#user_password'), confirmation = form.find('input#user_password_confirmation');
var label = $('label[for="user_password"]');

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

0 comments on commit d11b382

Please sign in to comment.