5

I have an ActiveRecord object and I would like to prevent it from being saved, without having permanent validations on the model. You used to be able to do something like this using errors.add but it doesn't look like it works anymore.

user = User.last
user.errors.add :name, "name doesn't rhyme with orange"
user.valid? # => true
user.save   # => true

or

user = User.last
user.errors.add :base, "my unique error"
user.valid? # => true
user.save   # => true

How can I prevent the user object from getting saved in Rails 3.2 without modifying it's model?

2
  • What's the reason you can't use a "permanent" validation? As I think doing what you're trying to do is moving some validation logic outside of the model which isn't a good idea. Commented Mar 12, 2012 at 21:22
  • 1
    I'm getting asked this question a lot in support of a Gem i wrote github.com/schneems/wicked people want to write one line validations that don't get called every time an object is saved, only in the context of the wizard. Looking to add this information to the documentation. It's also possible via metaprogramming to not know what model we're updating until run-time. A good general way to prevent AR objects from being saved when errors are added would be very helpful, and match previous behavior of Rails. Regardless of why, the question of how will still stand. Commented Mar 12, 2012 at 23:01

3 Answers 3

9

You can set errors, but do it within a validate method, e.g.:

validate :must_rhyme_with_orange

def must_rhyme_with_orange
  unless rhymes_with_orange?
    errors.add(:name, "doesn't rhyme with orange")
  end
end

If you want to conditionally run the validation, one trick is to use attr_accessor and a guard condition:

attr_accessor :needs_rhyming

validate :must_rhyme_with_orange, :if => Proc.new {|o| o.needs_rhyming}

> u = User.last
> u.needs_rhyming = true
> u.valid? # false
Sign up to request clarification or add additional context in comments.

Comments

2

Your issue is running valid? will rerun the validations.. resetting your errors.

     pry(main)> u.errors[:base] << "This is some custom error message"
     => ["This is some custom error message"]
     pry(main)> u.errors
     => {:base=>["This is some custom error message"]}
     pry(main)> u.valid?
     => true
     pry(main)> u.errors
     => {}
     pry(main)> 

Instead, just check if u.errors.blank?

2 Comments

That won't work for this particular situation, I don't want to change expected functionality, also since the user could save before I got the object the errors would be cleared anyway. Thanks for the response though. Also, pry is awesome...glad you're using it :)
NP, you simply can't do what you want then. not with out actually adding a validation to the model. Which you could do by including a mixin to the model class.
1

This is a slight deviation from the original question, but I found this post after trying a few things. Rails has built in functionality to reject an object from saving if it has the _destroy attribute assigned as true. Quite helpful if you're handling model creation on the controller level.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.