Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails model.valid? flushing custom errors and falsely returning true

I am trying to add a custom error to an instance of my User model, but when I call valid? it is wiping the custom errors and returning true.

[99] pry(main)> u.email = "[email protected]"
"[email protected]"

[100] pry(main)> u.status = 1
1

[101] pry(main)> u.valid?
true

[102] pry(main)> u.errors.add(:status, "must be YES or NO")
[
    [0] "must be YES or NO"
]

[103] pry(main)> u.errors
#<ActiveModel::Errors:[...]@messages={:status=>["must be YES or NO"]}>

[104] pry(main)> u.valid?
true

[105] pry(main)> u.errors
#<ActiveModel::Errors:[...]@messages={}>

If I use the validate method from within the model, then it works, but this specific validation is being added from within a different method (which requires params to be passed):

User

def do_something_with(arg1, arg2)
  errors.add(:field, "etc") if arg1 != arg2
end

Because of the above, user.valid? is returning true even when that error is added to the instance.

like image 923
Damien Roche Avatar asked Dec 14 '12 13:12

Damien Roche


2 Answers

In ActiveModel, valid? is defined as following:

def valid?(context = nil)
  current_context, self.validation_context = validation_context, context
  errors.clear
  run_validations!
ensure
  self.validation_context = current_context
end

So existing errors are cleared is expected. You have to put all your custom validations into some validate callbacks. Like this:

validate :check_status

def check_status
  errors.add(:status, "must be YES or NO") unless ['YES', 'NO'].include?(status)
end
like image 70
Yanhao Avatar answered Nov 18 '22 23:11

Yanhao


If you want to force your model to show the errors you could do something as dirty as this:

your_object = YourModel.new 
your_object.add(:your_field, "your message")
your_object.define_singleton_method(:valid?) { false }
# later on...
your_object.valid?
# => false
your_object.errors
# => {:your_field =>["your message"]} 

The define_singleton_method method can override the .valid? behaviour.

like image 40
Leandro Gerhardinger Avatar answered Nov 19 '22 01:11

Leandro Gerhardinger