valid? now recursively checks casted models. Added better validation spec coverage.
This commit is contained in:
parent
4a4cae0d95
commit
9a026997dd
4 changed files with 106 additions and 26 deletions
|
@ -115,8 +115,7 @@ module CouchRest
|
||||||
# Check if a resource is valid in a given context
|
# Check if a resource is valid in a given context
|
||||||
#
|
#
|
||||||
def valid?(context = :default)
|
def valid?(context = :default)
|
||||||
result = self.class.validators.execute(context, self)
|
recursive_valid?(self, context, true)
|
||||||
result && validate_casted_arrays
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# checking on casted objects
|
# checking on casted objects
|
||||||
|
@ -133,29 +132,22 @@ module CouchRest
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
# Begin a recursive walk of the model checking validity
|
|
||||||
#
|
|
||||||
def all_valid?(context = :default)
|
|
||||||
recursive_valid?(self, context, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Do recursive validity checking
|
# Do recursive validity checking
|
||||||
#
|
#
|
||||||
def recursive_valid?(target, context, state)
|
def recursive_valid?(target, context, state)
|
||||||
valid = state
|
valid = state
|
||||||
target.instance_variables.each do |ivar|
|
target.each do |key, prop|
|
||||||
ivar_value = target.instance_variable_get(ivar)
|
if prop.is_a?(Array)
|
||||||
if ivar_value.validatable?
|
prop.each do |item|
|
||||||
valid = valid && recursive_valid?(ivar_value, context, valid)
|
|
||||||
elsif ivar_value.respond_to?(:each)
|
|
||||||
ivar_value.each do |item|
|
|
||||||
if item.validatable?
|
if item.validatable?
|
||||||
valid = valid && recursive_valid?(item, context, valid)
|
valid = recursive_valid?(item, context, valid) && valid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
elsif prop.validatable?
|
||||||
|
valid = recursive_valid?(prop, context, valid) && valid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return valid && target.valid?
|
target.class.validators.execute(context, target) && valid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,15 +210,6 @@ module CouchRest
|
||||||
end # end
|
end # end
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
all = "all_valid_for_#{context.to_s}?" # all_valid_for_signup?
|
|
||||||
if !self.instance_methods.include?(all)
|
|
||||||
class_eval <<-EOS, __FILE__, __LINE__
|
|
||||||
def #{all} # def all_valid_for_signup?
|
|
||||||
all_valid?('#{context.to_s}'.to_sym) # all_valid?('signup'.to_sym)
|
|
||||||
end # end
|
|
||||||
EOS
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a new validator of the given klazz and push it onto the
|
# Create a new validator of the given klazz and push it onto the
|
||||||
|
|
|
@ -205,7 +205,57 @@ describe CouchRest::CastedModel do
|
||||||
cat.masters.push Person.new
|
cat.masters.push Person.new
|
||||||
cat.should be_valid
|
cat.should be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "calling valid?" do
|
||||||
|
before :each do
|
||||||
|
@cat = Cat.new
|
||||||
|
@toy1 = CatToy.new
|
||||||
|
@toy2 = CatToy.new
|
||||||
|
@toy3 = CatToy.new
|
||||||
|
@cat.favorite_toy = @toy1
|
||||||
|
@cat.toys << @toy2
|
||||||
|
@cat.toys << @toy3
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "on the top document" do
|
||||||
|
it "should put errors on all invalid casted models" do
|
||||||
|
@cat.should_not be_valid
|
||||||
|
@cat.errors.should_not be_empty
|
||||||
|
@toy1.errors.should_not be_empty
|
||||||
|
@toy2.errors.should_not be_empty
|
||||||
|
@toy3.errors.should_not be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not put errors on valid casted models" do
|
||||||
|
@toy1.name = "Feather"
|
||||||
|
@toy2.name = "Twine"
|
||||||
|
@cat.should_not be_valid
|
||||||
|
@cat.errors.should_not be_empty
|
||||||
|
@toy1.errors.should be_empty
|
||||||
|
@toy2.errors.should be_empty
|
||||||
|
@toy3.errors.should_not be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "on a casted model property" do
|
||||||
|
it "should only validate itself" do
|
||||||
|
@toy1.should_not be_valid
|
||||||
|
@toy1.errors.should_not be_empty
|
||||||
|
@cat.errors.should be_empty
|
||||||
|
@toy2.errors.should be_empty
|
||||||
|
@toy3.errors.should be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "on a casted model inside a casted collection" do
|
||||||
|
it "should only validate itself" do
|
||||||
|
@toy2.should_not be_valid
|
||||||
|
@toy2.errors.should_not be_empty
|
||||||
|
@cat.errors.should be_empty
|
||||||
|
@toy1.errors.should be_empty
|
||||||
|
@toy3.errors.should be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
||||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||||
|
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||||
|
|
||||||
|
|
||||||
describe "ExtendedDocument" do
|
describe "ExtendedDocument" do
|
||||||
|
@ -561,4 +562,49 @@ describe "ExtendedDocument" do
|
||||||
@doc.other_arg.should == "foo-foo"
|
@doc.other_arg.should == "foo-foo"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "recursive validation on an extended document" do
|
||||||
|
before :each do
|
||||||
|
reset_test_db!
|
||||||
|
@cat = Cat.new(:name => 'Sockington')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not save if a nested casted model is invalid" do
|
||||||
|
@cat.favorite_toy = CatToy.new
|
||||||
|
@cat.should_not be_valid
|
||||||
|
@cat.save.should be_false
|
||||||
|
lambda{@cat.save!}.should raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should save when nested casted model is valid" do
|
||||||
|
@cat.favorite_toy = CatToy.new(:name => 'Squeaky')
|
||||||
|
@cat.should be_valid
|
||||||
|
@cat.save.should be_true
|
||||||
|
lambda{@cat.save!}.should_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not save when nested collection contains an invalid casted model" do
|
||||||
|
@cat.toys = [CatToy.new(:name => 'Feather'), CatToy.new]
|
||||||
|
@cat.should_not be_valid
|
||||||
|
@cat.save.should be_false
|
||||||
|
lambda{@cat.save!}.should raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should save when nested collection contains valid casted models" do
|
||||||
|
@cat.toys = [CatToy.new(:name => 'feather'), CatToy.new(:name => 'ball-o-twine')]
|
||||||
|
@cat.should be_valid
|
||||||
|
@cat.save.should be_true
|
||||||
|
lambda{@cat.save!}.should_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not fail if the nested casted model doesn't have validation" do
|
||||||
|
Cat.property :trainer, :cast_as => 'Person'
|
||||||
|
Cat.validates_present :name
|
||||||
|
cat = Cat.new(:name => 'Mr Bigglesworth')
|
||||||
|
cat.trainer = Person.new
|
||||||
|
cat.trainer.validatable?.should be_false
|
||||||
|
cat.should be_valid
|
||||||
|
cat.save.should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
1
spec/fixtures/more/cat.rb
vendored
1
spec/fixtures/more/cat.rb
vendored
|
@ -6,6 +6,7 @@ class Cat < CouchRest::ExtendedDocument
|
||||||
|
|
||||||
property :name
|
property :name
|
||||||
property :toys, :cast_as => ['CatToy'], :default => []
|
property :toys, :cast_as => ['CatToy'], :default => []
|
||||||
|
property :favorite_toy, :cast_as => 'CatToy'
|
||||||
end
|
end
|
||||||
|
|
||||||
class CatToy < Hash
|
class CatToy < Hash
|
||||||
|
|
Loading…
Add table
Reference in a new issue