Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Added validates_associated that enables validation of objects in an u…
…nsaved association rails#398 [Tim Bates]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@418 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Jan 15, 2005
1 parent 823554e commit 51390b8
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
9 changes: 9 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,14 @@
*SVN*

* Added validates_associated that enables validation of objects in an unsaved association #398 [Tim Bates]. Example:

class Book < ActiveRecord::Base
has_many :pages
belongs_to :library

validates_associated :pages, :library
end

* Added support for associating unsaved objects #402 [Tim Bates]. Rules that govern this addition:

== Unsaved objects and associations
Expand Down
33 changes: 33 additions & 0 deletions activerecord/lib/active_record/validations.rb
Expand Up @@ -271,6 +271,39 @@ def validates_inclusion_of(*attr_names)
end
end
end

# Validates whether the associated object or objects are all themselves valid. Works with any kind of assocation.
#
# class Book < ActiveRecord::Base
# has_many :pages
# belongs_to :library
#
# validates_associated :pages, :library
# end
#
# Warning: If, after the above definition, you then wrote:
#
# class Page < ActiveRecord::Base
# belongs_to :book
#
# validates_associated :book
# end
#
# this would specify a circular dependency and cause infinite recursion. The Rails team recommends against this practice.
#
# Configuration options:
# * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
def validates_associated(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)

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?) }
}))
end
end


private
Expand Down
21 changes: 21 additions & 0 deletions activerecord/test/validations_test.rb
Expand Up @@ -389,6 +389,27 @@ def test_validates_length_of_custom_errors_for_is_with_wrong_length
assert_equal "hoo 5", t.errors["title"]
end

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!")]
assert !t.valid?
assert t.errors.on(:replies)
r.content = "non-empty"
assert t.valid?
end

def test_validates_associated_one
Reply.validates_associated( :topic )
Topic.validates_presence_of( :content )
r = Reply.create("title" => "A reply", "content" => "with content!")
r.topic = Topic.create("title" => "uhohuhoh")
assert !r.valid?
assert r.errors.on(:topic)
r.topic.content = "non-empty"
assert r.valid?
end

def test_throw_away_typing
d = Developer.create "name" => "David", "salary" => "100,000"
assert !d.valid?
Expand Down

0 comments on commit 51390b8

Please sign in to comment.