From 63255b80e40daec4cb6789b0649ef55aaa018248 Mon Sep 17 00:00:00 2001 From: Andy Selvig Date: Fri, 19 Dec 2014 20:58:56 -0600 Subject: [PATCH] :required => true now uses the not_null validator (not presence) Fixes #110 --- lib/no_brainer/document.rb | 4 +- lib/no_brainer/document/validation.rb | 7 +- .../document/validation/not_null.rb | 15 ++++ .../document/{ => validation}/uniqueness.rb | 4 +- lib/no_brainer/locale/en.yml | 1 + .../integration/validation/definition_spec.rb | 82 +++++++++++++++++++ .../{ => validation}/uniqueness_spec.rb | 2 +- .../{ => validation}/validation_spec.rb | 11 +-- 8 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 lib/no_brainer/document/validation/not_null.rb rename lib/no_brainer/document/{ => validation}/uniqueness.rb (95%) create mode 100644 spec/integration/validation/definition_spec.rb rename spec/integration/{ => validation}/uniqueness_spec.rb (99%) rename spec/integration/{ => validation}/validation_spec.rb (95%) diff --git a/lib/no_brainer/document.rb b/lib/no_brainer/document.rb index 707e055a13..5b096a07e4 100644 --- a/lib/no_brainer/document.rb +++ b/lib/no_brainer/document.rb @@ -4,8 +4,8 @@ module NoBrainer::Document extend ActiveSupport::Concern extend NoBrainer::Autoload - autoload_and_include :Core, :StoreIn, :InjectionLayer, :Attributes, :Readonly, :Validation, - :Persistance, :Types, :Uniqueness, :Callbacks, :Dirty, :PrimaryKey, + autoload_and_include :Core, :StoreIn, :InjectionLayer, :Attributes, :Readonly, + :Persistance, :Validation, :Types, :Callbacks, :Dirty, :PrimaryKey, :Association, :Serialization, :Criteria, :Polymorphic, :Index, :Aliases, :MissingAttributes, :LazyFetch, :AtomicOps diff --git a/lib/no_brainer/document/validation.rb b/lib/no_brainer/document/validation.rb index 0b79f689b0..41eab64521 100644 --- a/lib/no_brainer/document/validation.rb +++ b/lib/no_brainer/document/validation.rb @@ -1,8 +1,11 @@ module NoBrainer::Document::Validation + extend NoBrainer::Autoload extend ActiveSupport::Concern include ActiveModel::Validations include ActiveModel::Validations::Callbacks + autoload_and_include :Uniqueness, :NotNull + included do # We don't want before_validation returning false to halt the chain. define_callbacks :validation, :skip_after_callbacks_if_terminated => true, @@ -12,7 +15,7 @@ module NoBrainer::Document::Validation def valid?(context=nil, options={}) context ||= new_record? ? :create : :update - # copy/pasted, because we need to have control on errors.clear + # XXX Monkey Patching, because we need to have control on errors.clear current_context, self.validation_context = validation_context, context errors.clear unless options[:clear_errors] == false run_validations! @@ -24,9 +27,9 @@ module ClassMethods def _field(attr, options={}) super validates(attr, :format => { :with => options[:format] }) if options.has_key?(:format) - validates(attr, :presence => options[:required]) if options.has_key?(:required) validates(attr, :uniqueness => options[:unique]) if options.has_key?(:unique) validates(attr, :uniqueness => options[:uniq]) if options.has_key?(:uniq) + validates(attr, :not_null => options[:required]) if options.has_key?(:required) validates(attr, :inclusion => {:in => options[:in]}) if options.has_key?(:in) validates(attr, options[:validates]) if options[:validates] end diff --git a/lib/no_brainer/document/validation/not_null.rb b/lib/no_brainer/document/validation/not_null.rb new file mode 100644 index 0000000000..09f8a57628 --- /dev/null +++ b/lib/no_brainer/document/validation/not_null.rb @@ -0,0 +1,15 @@ +module NoBrainer::Document::Validation::NotNull + extend ActiveSupport::Concern + + module ClassMethods + def validates_not_null(*attr_names) + validates_with(NotNullValidator, _merge_attributes(attr_names)) + end + end + + class NotNullValidator < ActiveModel::EachValidator + def validate_each(doc, attr, value) + doc.errors.add(attr, :undefined, options) if value.nil? + end + end +end diff --git a/lib/no_brainer/document/uniqueness.rb b/lib/no_brainer/document/validation/uniqueness.rb similarity index 95% rename from lib/no_brainer/document/uniqueness.rb rename to lib/no_brainer/document/validation/uniqueness.rb index e2a80dcc30..967480c68c 100644 --- a/lib/no_brainer/document/uniqueness.rb +++ b/lib/no_brainer/document/validation/uniqueness.rb @@ -1,4 +1,4 @@ -module NoBrainer::Document::Uniqueness +module NoBrainer::Document::Validation::Uniqueness extend ActiveSupport::Concern def _create(options={}) @@ -51,7 +51,7 @@ def unlock_unique_fields module ClassMethods def validates_uniqueness_of(*attr_names) - validates_with UniquenessValidator, _merge_attributes(attr_names) + validates_with(UniquenessValidator, _merge_attributes(attr_names)) end def inherited(subclass) diff --git a/lib/no_brainer/locale/en.yml b/lib/no_brainer/locale/en.yml index 3b2b929893..29f8a49da7 100644 --- a/lib/no_brainer/locale/en.yml +++ b/lib/no_brainer/locale/en.yml @@ -3,3 +3,4 @@ en: messages: taken: "is already taken" invalid_type: "should be a %{type}" + undefined: "must be defined" diff --git a/spec/integration/validation/definition_spec.rb b/spec/integration/validation/definition_spec.rb new file mode 100644 index 0000000000..86cd03efc7 --- /dev/null +++ b/spec/integration/validation/definition_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe 'definition validator' do + before { load_simple_document } + + shared_examples_for "not_null validation" do + it 'cannot save without setting a value' do + doc = SimpleDocument.new + doc.valid?.should == false + expect { doc.save }.to raise_error(NoBrainer::Error::DocumentInvalid) + doc.errors.full_messages.first.should == 'Field1 must be defined' + end + + it 'cannot save a nil value' do + doc = SimpleDocument.new(:field1 => nil) + doc.valid?.should == false + expect { doc.save }.to raise_error(NoBrainer::Error::DocumentInvalid) + end + + it 'can save an empty string' do + doc = SimpleDocument.new(:field1 => '') + doc.valid?.should == true + end + + it 'can save a false value' do + doc = SimpleDocument.new(:field1 => false) + doc.valid?.should == true + end + + it 'can save an empty array' do + doc = SimpleDocument.new(:field1 => []) + doc.valid?.should == true + end + end + + shared_examples_for "presence validation" do + it 'cannot save without setting a value' do + doc = SimpleDocument.new + doc.valid?.should == false + expect { doc.save }.to raise_error(NoBrainer::Error::DocumentInvalid) + doc.errors.full_messages.first.should == "Field1 can't be blank" + end + + it 'cannot save a nil value' do + doc = SimpleDocument.new(:field1 => nil) + doc.valid?.should == false + expect { doc.save }.to raise_error(NoBrainer::Error::DocumentInvalid) + end + + it 'cannot save an empty string' do + doc = SimpleDocument.new(:field1 => '') + doc.valid?.should == false + expect { doc.save }.to raise_error(NoBrainer::Error::DocumentInvalid) + end + + it 'cannot save a false value' do + doc = SimpleDocument.new(:field1 => false) + doc.valid?.should == false + expect { doc.save }.to raise_error(NoBrainer::Error::DocumentInvalid) + end + + it 'cannot save an empty array' do + doc = SimpleDocument.new(:field1 => []) + doc.valid?.should == false + expect { doc.save }.to raise_error(NoBrainer::Error::DocumentInvalid) + end + end + + context 'with validates_not_null' do + before { SimpleDocument.validates_not_null :field1 } + it_behaves_like "not_null validation" + end + + context 'with validates_presence_of' do + before { SimpleDocument.validates_presence_of :field1 } + it_behaves_like "presence validation" + end + + context 'with :required => true' do + before { SimpleDocument.field :field1, :required => :not_null } + end +end diff --git a/spec/integration/uniqueness_spec.rb b/spec/integration/validation/uniqueness_spec.rb similarity index 99% rename from spec/integration/uniqueness_spec.rb rename to spec/integration/validation/uniqueness_spec.rb index 07bf163326..f16bf7a881 100644 --- a/spec/integration/uniqueness_spec.rb +++ b/spec/integration/validation/uniqueness_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'NoBrainer callbacks' do +describe 'uniqueness validator' do before { load_simple_document } context 'with validates_uniqueness_of' do diff --git a/spec/integration/validation_spec.rb b/spec/integration/validation/validation_spec.rb similarity index 95% rename from spec/integration/validation_spec.rb rename to spec/integration/validation/validation_spec.rb index b3c8d34561..8ac4aa6702 100644 --- a/spec/integration/validation_spec.rb +++ b/spec/integration/validation/validation_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'NoBrainer callbacks' do +describe 'validations' do before { load_simple_document } context 'when using a simple validation' do @@ -155,15 +155,6 @@ def some_validator end end - context 'when using required on the field' do - before { SimpleDocument.field :field1, :required => true } - - it 'validates' do - SimpleDocument.new(:field1 => nil).valid?.should == false - SimpleDocument.new(:field1 => 'ohai').valid?.should == true - end - end - context 'when using format on the field' do before { SimpleDocument.field :field1, :format => /\A[a-z]+\z/ }