Permalink
Browse files

Merge pull request #302 from ares/239-validates_with_if_and_unless-re…

…based

Enabled if and unless specification
  • Loading branch information...
2 parents fa9aa7f + 1e83196 commit 85e8ec91146833303f0b96045d7309e83d123ecc @bcardarella bcardarella committed Mar 28, 2012
@@ -97,8 +97,22 @@ def filter_validators(method, filters)
unfiltered_validators.delete(validator.first)
end
else
- if (conditional = (validator.last[:if] || validator.last[:unless])) && conditional.is_a?(Symbol) && !conditional_method_is_change_method?(conditional, method)
- unfiltered_validators.delete(validator.first)
+ if (conditional = (validator.last[:if] || validator.last[:unless]))
+ result = case conditional
+ when Symbol then
+ if @object.respond_to?(conditional)
+ @object.send(conditional)
+ else
+ raise(ArgumentError, "unknown method called '#{conditional}'")
+ end
+ when String then eval(conditional)
+ when Proc then conditional.call(@object)
+ end
+
+ # :if was specified and result is false OR :unless was specified and result was true
+ if (validator.last[:if] && !result) || (validator.last[:unless] && result)
+ unfiltered_validators.delete(validator.first)
+ end
end
end
unfiltered_validators[validator.first].delete(:if) if unfiltered_validators[validator.first]
@@ -8,6 +8,10 @@ def client_side_hash(model, attribute)
{ :message => model.errors.generate_message(attribute, message_type, options) }.merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
end
+ def copy_conditional_attributes(to, from)
+ [:if, :unless].each { |key| to[key] = from[key] if from[key].present? }
+ end
+
private
def message_type
@@ -16,6 +16,8 @@ def client_side_hash(model, attribute)
end
end
+ copy_conditional_attributes(hash, options)
+
hash
end
@@ -23,6 +23,8 @@ def client_side_hash(model, attribute)
end
end
+ copy_conditional_attributes(hash, options)
+
hash
end
@@ -355,12 +355,12 @@ def test_time_zone_select
assert_equal expected, output_buffer
end
- def test_conditional_validators_should_be_filtered
+ def test_conditional_validators_should_be_filtered_based_on_symbol_condition_true
hash = {
:cost => {
:presence => {
:message => "can't be blank",
- :unless => :do_not_validate?
+ :unless => :do_validate?
}
},
:title => {
@@ -380,9 +380,182 @@ def test_conditional_validators_should_be_filtered
concat f.text_field(:title)
end
- validators = {}
+ validators = {
+ 'post[title]' => {:presence => {:message => "can't be blank"}}
+ }
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
+ %{<input id="post_cost" name="post[cost]" size="30" type="text" />} +
+ %{<input data-validate="true" id="post_title" name="post[title]" size="30" type="text" />}
+ end
+ assert_equal expected, output_buffer
+ end
+
+ def test_conditional_validators_should_be_filtered_based_on_symbol_condition_false
+ hash = {
+ :cost => {
+ :presence => {
+ :message => "can't be blank",
+ :unless => :do_not_validate?
+ }
+ },
+ :title => {
+ :presence => {
+ :message => "can't be blank",
+ :if => :do_not_validate?
+ }
+ }
+ }
+
+ @post.title = nil
+ @post.stubs(:do_not_validate?).returns(false)
+ @post.stubs(:do_validate?).returns(true)
+ @post.stubs(:client_side_validation_hash).returns(hash)
+ form_for(@post, :validate => true) do |f|
+ concat f.text_field(:cost)
+ concat f.text_field(:title)
+ end
+
+ validators = {
+ 'post[cost]' => {: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_cost" name="post[cost]" size="30" type="text" />} +
+ %{<input id="post_title" name="post[title]" size="30" type="text" />}
+ end
+ assert_equal expected, output_buffer
+ end
+
+ def test_conditional_validators_should_be_filtered_based_on_string_condition_true
+ hash = {
+ :cost => {
+ :presence => {
+ :message => "can't be blank",
+ :unless => 'true'
+ }
+ },
+ :title => {
+ :presence => {
+ :message => "can't be blank",
+ :if => 'true'
+ }
+ }
+ }
+
+ @post.title = nil
+ @post.stubs(:client_side_validation_hash).returns(hash)
+ form_for(@post, :validate => true) do |f|
+ concat f.text_field(:cost)
+ concat f.text_field(:title)
+ end
+
+ validators = {
+ 'post[title]' => {:presence => {:message => "can't be blank"}}
+ }
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
+ %{<input id="post_cost" name="post[cost]" size="30" type="text" />} +
+ %{<input data-validate="true" id="post_title" name="post[title]" size="30" type="text" />}
+ end
+ assert_equal expected, output_buffer
+ end
+
+ def test_conditional_validators_should_be_filtered_based_on_string_condition_false
+ hash = {
+ :cost => {
+ :presence => {
+ :message => "can't be blank",
+ :unless => 'false'
+ }
+ },
+ :title => {
+ :presence => {
+ :message => "can't be blank",
+ :if => 'false'
+ }
+ }
+ }
+
+ @post.title = nil
+ @post.stubs(:client_side_validation_hash).returns(hash)
+ form_for(@post, :validate => true) do |f|
+ concat f.text_field(:cost)
+ concat f.text_field(:title)
+ end
+
+ validators = {
+ 'post[cost]' => {: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_cost" name="post[cost]" size="30" type="text" />} +
+ %{<input id="post_title" name="post[title]" size="30" type="text" />}
+ end
+ assert_equal expected, output_buffer
+ end
+
+ def test_conditional_validators_should_be_filtered_based_on_proc_condition_true
+ hash = {
+ :cost => {
+ :presence => {
+ :message => "can't be blank",
+ :unless => Proc.new { |o| o.do_validate? }
+ }
+ },
+ :title => {
+ :presence => {
+ :message => "can't be blank",
+ :if => Proc.new { |o| o.do_validate? }
+ }
+ }
+ }
+
+ @post.title = nil
+ @post.stubs(:do_not_validate?).returns(false)
+ @post.stubs(:do_validate?).returns(true)
+ @post.stubs(:client_side_validation_hash).returns(hash)
+ form_for(@post, :validate => true) do |f|
+ concat f.text_field(:cost)
+ concat f.text_field(:title)
+ end
+
+ validators = {
+ 'post[title]' => {:presence => {:message => "can't be blank"}}
+ }
expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
%{<input id="post_cost" name="post[cost]" size="30" type="text" />} +
+ %{<input data-validate="true" id="post_title" name="post[title]" size="30" type="text" />}
+ end
+ assert_equal expected, output_buffer
+ end
+
+ def test_conditional_validators_should_be_filtered_based_on_proc_condition_false
+ hash = {
+ :cost => {
+ :presence => {
+ :message => "can't be blank",
+ :unless => Proc.new { |o| o.do_not_validate? }
+ }
+ },
+ :title => {
+ :presence => {
+ :message => "can't be blank",
+ :if => Proc.new { |o| o.do_not_validate? }
+ }
+ }
+ }
+
+ @post.title = nil
+ @post.stubs(:do_not_validate?).returns(false)
+ @post.stubs(:do_validate?).returns(true)
+ @post.stubs(:client_side_validation_hash).returns(hash)
+ form_for(@post, :validate => true) do |f|
+ concat f.text_field(:cost)
+ concat f.text_field(:title)
+ end
+
+ validators = {
+ 'post[cost]' => {: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_cost" name="post[cost]" size="30" type="text" />} +
%{<input id="post_title" name="post[title]" size="30" type="text" />}
end
assert_equal expected, output_buffer
@@ -579,6 +752,9 @@ def test_conditional_validator_ignored_when_using_changed_helpers
}
@post.title = nil
+ # we don't have _changed? methods by default so we must stub them
+ @post.stubs(:title_changed?).returns(true)
+ @post.stubs(:cost_changed?).returns(false)
@post.stubs(:client_side_validation_hash).returns(hash)
form_for(@post, :validate => true) do |f|
concat f.text_field(:cost)
@@ -613,6 +789,9 @@ def test_conditional_validator_ignored_when_using_changed_helpers_and_forcing_va
}
@post.title = nil
+ # we don't have _changed? methods by default so we must stub them
+ @post.stubs(:title_changed?).returns(true)
+ @post.stubs(:cost_changed?).returns(false)
@post.stubs(:client_side_validation_hash).returns(hash)
form_for(@post, :validate => true) do |f|
concat f.text_field(:cost, :validate => true)

0 comments on commit 85e8ec9

Please sign in to comment.