aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG8
-rwxr-xr-xactiverecord/lib/active_record/validations.rb6
-rwxr-xr-xactiverecord/test/validations_test.rb19
3 files changed, 28 insertions, 5 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index e2dfa77e0b..d05ecfbe31 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,13 @@
*SVN*
+* Added that validates_* now accept blocks to perform validations #618 [Tim Bates]. Example:
+
+ class Person < ActiveRecord::Base
+ validate { |person| person.errors.add("title", "will never be valid") if SHOULD_NEVER_BE_VALID }
+ end
+
+* Addded validation for validate all the associated objects before declaring failure with validates_associated #618 [Tim Bates]
+
* Added keyword-style approach to defining the custom relational bindings #545 [Jamis Buck]. Example:
class Project < ActiveRecord::Base
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index 1e5d4287b0..a7811e50ac 100755
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -51,7 +51,7 @@ module ActiveRecord
alias_method :update_attribute_without_validation_skipping, :update_attribute
alias_method :update_attribute, :update_attribute_with_validation_skipping
- VALIDATIONS.each { |vd| base.class_eval("def self.#{vd}(*methods) write_inheritable_array(\"#{vd}\", methods - (read_inheritable_attribute(\"#{vd}\") || [])) end") }
+ VALIDATIONS.each { |vd| base.class_eval("def self.#{vd}(*methods, &block) write_inheritable_array(\"#{vd}\", methods + [block].compact - (read_inheritable_attribute(\"#{vd}\") || [])) end") }
end
base.extend(ClassMethods)
@@ -300,7 +300,7 @@ module ActiveRecord
for attr_name in attr_names
class_eval(%(#{validation_method(configuration[:on])} %{
errors.add("#{attr_name}", "#{configuration[:message]}") unless
- (#{attr_name}.is_a?(Array) ? #{attr_name} : [#{attr_name}]).inject(true){ |memo, record| memo and (record.nil? or record.valid?) }
+ (#{attr_name}.is_a?(Array) ? #{attr_name} : [#{attr_name}]).inject(true){ |memo, record| (record.nil? or record.valid?) and memo }
}))
end
end
@@ -378,7 +378,7 @@ module ActiveRecord
eval(validation, binding)
elsif validation_block?(validation)
validation.call(self)
- elsif filter_class?(validation, validation_method)
+ elsif validation_class?(validation, validation_method)
validation.send(validation_method, self)
else
raise(
diff --git a/activerecord/test/validations_test.rb b/activerecord/test/validations_test.rb
index 052cf3d6ca..7ac93b43fb 100755
--- a/activerecord/test/validations_test.rb
+++ b/activerecord/test/validations_test.rb
@@ -392,10 +392,12 @@ class ValidationsTest < Test::Unit::TestCase
def test_validates_associated_many
Topic.validates_associated( :replies )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
- t.replies << [r = Reply.create("title" => "A reply"), Reply.create("title" => "Another reply", "content" => "with content!")]
+ t.replies << [r = Reply.create("title" => "A reply"), r2 = Reply.create("title" => "Another reply")]
assert !t.valid?
assert t.errors.on(:replies)
- r.content = "non-empty"
+ assert_equal 1, r.errors.count # make sure all associated objects have been validated
+ assert_equal 1, r2.errors.count
+ r.content = r2.content = "non-empty"
assert t.valid?
end
@@ -410,6 +412,19 @@ class ValidationsTest < Test::Unit::TestCase
assert r.valid?
end
+ def test_validate_block
+ Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
+ t = Topic.create("title" => "Title", "content" => "whatever")
+ assert !t.valid?
+ assert t.errors.on(:title)
+ assert_equal "will never be valid", t.errors["title"]
+ end
+
+ def test_invalid_validator
+ Topic.validate 3
+ assert_raise(ActiveRecord::ActiveRecordError) { t = Topic.create }
+ end
+
def test_throw_away_typing
d = Developer.create "name" => "David", "salary" => "100,000"
assert !d.valid?