Skip to content

Added absence validator for active model. #7155

Closed
wants to merge 14 commits into from
@robotex82

Please accept my pull request for an absence validator.

See following discussion: https://groups.google.com/forum/#!topic/rubyonrails-core/KS_Olcnlw8w

I included passing tests and docs (Copied and adapted from the presence validator).

Thanks!

Saludos,

Roberto

@paneq
paneq commented Jul 25, 2012

+1

@dolzenko

+1 Can confirm that needed this in almost every project with relatively complex models

@robotex82

I use it on trees, where i need attributes to be empty on roots. But I think, there should be better examples.

Anyone?

@chancancode
Ruby on Rails member

With the strict option set to true, this could be used to verify the integrity of your models... so I'm +1 on this.

@kendagriff

+1 – Require first and last names for users older than 13, but prevent update for younger than 13.

@frodsan frodsan commented on the diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
+ end
+
+ def test_accepts_array_arguments
+ Topic.validates_absence_of %w(title content)
+ t = Topic.new
+
+ t.title = "foo"
+ t.content = "bar"
+
+ assert t.invalid?
+ assert_equal ["must be blank"], t.errors[:title]
+ assert_equal ["must be blank"], t.errors[:content]
+ end
+
+ def test_validates_acceptance_of_with_custom_error_using_quotes
+ Person.validates_absence_of :karma, :message => "This string contains 'single' and \"double\" quotes"
@frodsan
frodsan added a note Oct 27, 2012

Please use 1.9 hash syntax. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@frodsan
frodsan commented Oct 27, 2012

I'm 👍 on this.

@frodsan frodsan commented on an outdated diff Oct 27, 2012
activemodel/lib/active_model/validations/absence.rb
@@ -0,0 +1,34 @@
+require 'active_support/core_ext/object/blank'
+
+module ActiveModel
+
+ # == Active Model Absence Validator
@frodsan
frodsan added a note Oct 27, 2012

Could you move this title to class AbsenceValidator?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@frodsan
frodsan commented Oct 27, 2012

@robotex82 Could you add a CHANGELOG entry please? Thanks!

@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
+require 'models/person'
+require 'models/custom_reader'
+
+class AbsenceValidationTest < ActiveModel::TestCase
+
+ teardown do
+ Topic.reset_callbacks(:validate)
+ Person.reset_callbacks(:validate)
+ CustomReader.reset_callbacks(:validate)
+ end
+
+ def test_validate_absences
+ Topic.validates_absence_of(:title, :content)
+
+ t = Topic.new
+
@carlosantoniodasilva
Ruby on Rails member

Remove blank line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on the diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
@@ -0,0 +1,90 @@
+# encoding: utf-8
+require 'cases/helper'
+
+require 'models/topic'
+require 'models/person'
+require 'models/custom_reader'
+
+class AbsenceValidationTest < ActiveModel::TestCase
+
@carlosantoniodasilva
Ruby on Rails member

Remove blank line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on the diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
+
+ t.title = ""
+ t.content = "something"
+
+ assert t.invalid?
+ assert_equal ["must be blank"], t.errors[:content]
+
+ t.content = ""
+
+ assert t.valid?
+ end
+
+ def test_accepts_array_arguments
+ Topic.validates_absence_of %w(title content)
+ t = Topic.new
+
@carlosantoniodasilva
Ruby on Rails member

Remove blank line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on the diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
+ def test_accepts_array_arguments
+ Topic.validates_absence_of %w(title content)
+ t = Topic.new
+
+ t.title = "foo"
+ t.content = "bar"
+
+ assert t.invalid?
+ assert_equal ["must be blank"], t.errors[:title]
+ assert_equal ["must be blank"], t.errors[:content]
+ end
+
+ def test_validates_acceptance_of_with_custom_error_using_quotes
+ Person.validates_absence_of :karma, :message => "This string contains 'single' and \"double\" quotes"
+ p = Person.new
+
@carlosantoniodasilva
Ruby on Rails member

Remove blank line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
+ def test_validates_acceptance_of_with_custom_error_using_quotes
+ Person.validates_absence_of :karma, :message => "This string contains 'single' and \"double\" quotes"
+ p = Person.new
+
+ p.karma = "good"
+
+ assert p.invalid?
+ assert_equal "This string contains 'single' and \"double\" quotes", p.errors[:karma].last
+ end
+
+ def test_validates_absence_of_for_ruby_class
+ Person.validates_absence_of :karma
+
+ p = Person.new
+
+ p.karma = "good"
@carlosantoniodasilva
Ruby on Rails member

Remove blank line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
+
+ p.karma = "good"
+
+ assert p.invalid?
+ assert_equal "This string contains 'single' and \"double\" quotes", p.errors[:karma].last
+ end
+
+ def test_validates_absence_of_for_ruby_class
+ Person.validates_absence_of :karma
+
+ p = Person.new
+
+ p.karma = "good"
+
+ assert p.invalid?
+
@carlosantoniodasilva
Ruby on Rails member

Remove blank line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Oct 27, 2012
...del/test/cases/validations/absence_validation_test.rb
+ assert_equal ["must be blank"], p.errors[:karma]
+
+ p.karma = nil
+ assert p.valid?
+ end
+
+ def test_validates_absence_of_for_ruby_class_with_custom_reader
+ CustomReader.validates_absence_of :karma
+
+ p = CustomReader.new
+
+ p[:karma] = "excellent"
+
+ assert p.invalid?
+
+ assert_equal ["must be blank"], p.errors[:karma]
@carlosantoniodasilva
Ruby on Rails member

Same thing for blank lines here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Oct 27, 2012
activemodel/lib/active_model/errors.rb
@@ -324,6 +324,19 @@ def add_on_blank(attributes, options = {})
add(attribute, :blank, options) if value.blank?
end
end
+
+ # Will add an error message to each of the attributes in +attributes+ that
+ # is not blank (using Object#blank?).
+ #
+ # person.errors.add_on_not_blank(:name)
+ # person.errors.messages
+ # # => { :name => ["must be blank"] }
+ def add_on_not_blank(attributes, options = {})
+ [attributes].flatten.each do |attribute|
+ value = @base.send(:read_attribute_for_validation, attribute)
+ add(attribute, :not_blank, options) unless value.blank?
+ end
+ end
@carlosantoniodasilva
Ruby on Rails member

I don't think we need to have this in here, I believe that should be handled by the validator itself in this case. There's no need to extend Errors API with this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva
Ruby on Rails member

I wonder if we should use present instead of not_blank, thoughts?

@robotex82 thanks!

@robotex82

Thank you guys!

Sorry, I have been busy all the time, but i'll have a look at your suggestions asap. Hopefully before next weekend.

Do you see any chance to have this merged into master for v4.0?

@carlosantoniodasilva
Ruby on Rails member

@robotex82 I believe so :)

@robotex82

I updated my local copy and changed add_on_not_blank to add_on_present.

I had some trouble with updating and rebasing - I admit, I lack experience on this topic - but I hope I didn't mess up.

Could someone please check my updated pull request?

What do I have to do next?

@carlosantoniodasilva
Ruby on Rails member

@robotex82 thanks, but apparently you have some commits that shouldn't be there, can you try a new rebase, so that we can see only your PR diff?

@robotex82

I did:

git rebase upstream/master
git push --force

is that correct?

Excuse my noobish questions! I googled for the correct process of updating forks, rebasing, etc. but it's still not really clear to me.

@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Nov 7, 2012
activemodel/lib/active_model/validations/absence.rb
@@ -0,0 +1,33 @@
+require 'active_support/core_ext/object/blank'
+
+module ActiveModel
+ module Validations
+ # == Active Model Absence Validator
@carlosantoniodasilva
Ruby on Rails member

You can remove this comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Nov 7, 2012
activemodel/lib/active_model/errors.rb
@@ -328,6 +328,19 @@ def add_on_blank(attributes, options = {})
end
end
+ # Will add an error message to each of the attributes in +attributes+ that
+ # is present (using Object#present?).
+ #
+ # person.errors.add_on_present(:name)
+ # person.errors.messages
+ # # => { :name => ["must be blank"] }
+ def add_on_present(attributes, options = {})
+ [attributes].flatten.each do |attribute|
@carlosantoniodasilva
Ruby on Rails member

Can use Array(attributes), it has changed these days in master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Nov 7, 2012
activemodel/lib/active_model/validations/absence.rb
@@ -0,0 +1,33 @@
+require 'active_support/core_ext/object/blank'
+
@carlosantoniodasilva
Ruby on Rails member

You don't need this require.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@carlosantoniodasilva
Ruby on Rails member

@robotex82 it's fine now, thanks. I added some comments, and we'll need a two changelog entries in Active Model, one for Errors#add_on_present and other for the validation itself, can you please add them, and squash your commits? Thanks.

@robotex82

Should I append or prepend to the changelog?

@carlosantoniodasilva
Ruby on Rails member

@robotex82 prepend, always at top :).

@robotex82 robotex82 Add `ActiveModel::Validations::AbsenceValidator`, a validator to chec…
…k the absence of attributes.

Add `ActiveModel::Errors#add_on_present` method. Adds error messages to present attributes.
072b977
@robotex82

Hope it's ok now.....

@carlosantoniodasilva
Ruby on Rails member

I added some minor comments, can you take a look at them before we merge? Also, what do you think about adding an example for the changelog entries, similar to the ones you added to the docs? (just look at other changelog examples to see how to format them).

Other than that, just squash your commits and we're good to go :). Thanks!

@robotex82

Well, I added the example to the changelog. But again I'm stuck with git :(

I have a commit history like that:

1a9f792 Updated changelog
072b977 Add `ActiveModel::Validations::AbsenceValidator`, a validator to check the  absence of attributes. Add `ActiveModel::Errors#add_on_present` method. Adds error messages to presen
c35fa0b Removed blank lines Changed add_on_not_blank to add_on_present
02e8148 Added absence validator for active model.
c233b2f Fix guides home links and maintain compatibility with small screens

So I thought I google how to squash commits. I tried some things but I keep getting errors or the commits don't go away.

So, please, could some of you experieced people, tell me how I package things up?

Thanks, and sorry again...squashing, rabaseing, etc. is new stuff to me.

@carlosantoniodasilva: I couldn't find your comments, where are they?

@carlosantoniodasilva
Ruby on Rails member

@robotex82 just look at the pull request Files Changed tab with the diff, and you'll see the comments (just ignore the "Remove blank line." ones).

Now about the rebase, Jon has just given a quick explanation here, but if you still have doubts, please let me know. Thanks!

@carlosantoniodasilva
Ruby on Rails member

@steveklabnik Ah true, I forgot that, awesome thanks ❤️

@steveklabnik
Ruby on Rails member

You didn't forget that at all; I saw this comment, was like "man, I really need to put this in a place where I can find it again," posted it, and then linked it here. ;)

@carlosantoniodasilva
Ruby on Rails member

Haha sorry, I thought I had seen that among your other contribution related posts. Awesome anyway, you were fast on that 😄

carlosantoniodasilva and others added some commits Nov 7, 2012
@carlosantoniodasilva carlosantoniodasilva Remove block given check from private find_with_ids
This is already handled by #find, it's a duplicate check, since
find_with_ids is not called from anywhere else.
838c5e8
@carlosantoniodasilva carlosantoniodasilva Use cached quoted_table_name instead of going through the connection 4995979
@carlosantoniodasilva carlosantoniodasilva Remove not used indifferent_access requires from Base and FinderMethods fda107b
@senny senny `plugin new` adds dummy app tasks when necessary.
Closes #8121

The `plugin new` generator always adds the dummy app rake tasks,
when a dummy app was created.
a085d27
@rafaelfranca rafaelfranca Add CHANGELOG entry for #8108 on master too.
[ci skip]
6f8b95c
Gabriel Sobrinho & Ricardo Henrique Add test to avoid regression of 58e48d5 50337da
@senny senny test case to lock down the behavior of #7842 4d10d8b
@senny senny routing prefix slash replacement is no longer necessary 4c14e05
@jcoglan jcoglan Store FlashHashes in the session as plain hashes rather than custom o…
…bjects with unstable class names and instance variables.

Refactor FlashHash to take values for its ivars in the constructor, to pretty up FlashHash.from_session_value.

Remove stale comment on FlashHash: it is no longer Marshaled in the session so we can change its implementation.

Remove blank lines I introduced in controller/test_case.rb.

Unit tests for FlashHash#to_session_value.

Put in a compatibility layer to accept FlashHash serializations from Rails 3.0+.

Test that Rails 3.2 session flashes are correctly converted to the new format.

Remove code path for processing Rails 3.0 FlashHashes since they can no longer deserialize.
f66ec25
@carlosantoniodasilva carlosantoniodasilva Remove free usage of #tap 9a68393
@robotex82 robotex82 Add `ActiveModel::Validations::AbsenceValidator`, a validator to chec…
…k the absence of attributes.

Add `ActiveModel::Errors#add_on_present` method. Adds error messages to present attributes.
64df864
@robotex82

This looks ....wrong?!

@carlosantoniodasilva
Ruby on Rails member

Looks like there are some extra commits now :)

@robotex82

OT: Time to read a book about GIT. Suggestions?

@steveklabnik
Ruby on Rails member
@robotex82

I read the section on rebasing, but I don't get this right. :(

How do we get this right? Should I create a completely new pull request?

@steveklabnik
Ruby on Rails member

@robotex82 Because it's been a month, and you're obviously having some trouble, and I had some time this morning, I took care of this.

You can see the commit here: d72a07f

I also took care of @frodsan 's comment about the 1.9 hash syntax, and double checked @carlosantoniodasilva 's comments about blank lines.

Thank you for your pull request, hopefully you will overcome the git beast next time ;)

@wilmoore

@robotex82: I highly recommend the Mastering Git series by @tlberglund and @matthewmccullough:

Full Disclosure: I know them both personally (and I appear in one of the videos) so I am a bit biased -- but trust me, watch these videos a few times through and you will level-up in your git-fu for sure.

@robotex82

Awesome, thank you guys! ❤️

Sorry for the late answer, but I've been very busy!

While checking the commit, I discovered, that the CHANGELOG is messed up a little bit:

Actual:

*   Add `ActiveModel::Validations::AbsenceValidator`, a validator to check the
    absence of attributes.

        class Person
          include ActiveModel::Validations

          attr_accessor :first_name
          validates_absence_of :first_name
        end

        person = Person.new
        person.first_name = "John"
        person.valid?
        # => false
        person.errors.messages
        # => {:first_name=>["must be blank"]}

    *Roberto Vasquez Angel*

*   `[attribute]_changed?` now returns `false` after a call to `reset_[attribute]!`

Shouldn't it be:

    *Roberto Vasquez Angel*

*   Add `ActiveModel::Validations::AbsenceValidator`, a validator to check the
    absence of attributes.

        class Person
          include ActiveModel::Validations

          attr_accessor :first_name
          validates_absence_of :first_name
        end

        person = Person.new
        person.first_name = "John"
        person.valid?
        # => false
        person.errors.messages
        # => {:first_name=>["must be blank"]}

*   `[attribute]_changed?` now returns `false` after a call to `reset_[attribute]!`

How do we get this right?

Thanks again!

@carlosantoniodasilva
Ruby on Rails member

Not sure what you mean, but the name goes after the change, at the end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.