views:

786

answers:

6

I'm working with Ruby on Rails and would like to validate two different models :

if (model1.valid? && model2.valid?)
...
end

However, "&&" operator uses short-circuit evaluation (i.e. it evaluates "model2.valid?" only if "model1.valid?" is true), which prevents model2.valids to be executed if model1 is not valid.

Is there an equivalent of "&&" which would not use short-circuit evaluation? I need the two expressions to be evaluated.

+1  A: 

Evaluate them separately and store the result in a variable. Then use a simple && between those booleans :)

Mehrdad Afshari
A: 

Thanks for this answer.

I had thought about this solution and will use it, but I wanted to know if a mysterious boolean operator could do that.

Paul Smith
+7  A: 

Try this:

([model1, model2].map(&:valid?)).all?

It'll return true if both are valid, and create the errors on both instances.

Mr. Matt
A: 

Instead of creating an extra array with map, you can pass a block to all?.

[model_instance_1, model_instance_2].all? {|i| i.valid? }
August Lilleaas
Samuel
Why does this answer have down-votes on it? Is there something wrong with this answer that isn't immediately obvious?
Eliza
Oh- that would be because this method short circuits...
Eliza
Paul Smith
@Paul Performance and obscurity. Symbol#to_proc was a lot slower than passing a block on older versions of ruby. (Not really an issue with 2 elements, though.) It's a relatively new addition to the core library leveraging old but not commonly used type coercion syntax.
cpm
+5  A: 

& works just fine.

irb(main):007:0> def a
irb(main):008:1> puts "a"
irb(main):009:1> false
irb(main):010:1> end
=> nil

irb(main):011:0> def b
irb(main):012:1> puts "b"
irb(main):013:1> true
irb(main):014:1> end
=> nil

irb(main):015:0> a && b
a
=> false

irb(main):016:0> a & b
a
b
=> false

irb(main):017:0> a and b
a
=> false
Paul Smith
valid is a method that runs the validations on an ActiveRecord instance, populating the associated errors so that they can be reported back to the user.
Mr. Matt
Mike Woodhouse
Good point Mr. Matt - reporting errors on both models simultaneously is a worthy goal. Removed the "bad code smell" comment :)
Paul Smith
@Mike: Interesting - I'll have to do more irb investigation. PS I love irb for investigating things like this!
Paul Smith
cpm
A: 

How about:

if [model1.valid?,model2.valid?].all?
  ...
end

Works for me.

malclocke