24

In my form I have a Select with three values: Apple, Banana and Cherry. If I choose Apple from the select I hide another Select- and a Text-field with some Javascript, because when Apple is chosen, there is no need to fill in these other two fields anymore.

So now I have a problem with validating my form when it's submitted. I've found some similar problems for example in the case of "Only validate a field if another is blank."

This problem was solved like this:

validates_presence_of :mobile_number, :unless => :home_phone?

So I've just tried the first thing which popped into my mind:

validates_presence_of :state, :granted_at, :if => :type != 1

But when I run it, I get this error:

undefined method `validate' for true:TrueClass

How can I conditionally perform a validation on a field based on whether or not another field has a particular value?

Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
TehQuila
  • 628
  • 1
  • 8
  • 19

4 Answers4

33

Because it is executable code you need to wrap it in a lambda or a Proc object like so:

validates_presence_of :state, :granted_at, :if => lambda { |o| o.type != 1 }

# alternatively:
..., :if => lambda { self.type != 1 }
..., :if => Proc.new { |o| o.type != 1 }
..., :if ->(o) { o.type != 1 }
Matt
  • 17,290
  • 7
  • 57
  • 71
  • thank you for the fast response :) but what contains this block variable "o"? the object which is being validated? – TehQuila Jan 13 '12 at 13:07
  • Yes, exactly. Also take a look at @Hauleth's answer where you can find other ways of solving your problem. The definitive reference can be found in the Rails API Documentation: http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html hope that helps. Furthermore I suggest you google for "ruby procs and blocks" to learn about the basic (ruby) building blocks behind this. Hope that helps. – Matt Jan 13 '12 at 19:17
26

You can use if flag and lambda:

validates_presence_of :state, :granted_at, :if => lambda {self.type != 1}

Or just create private method:

validates_presence_of :state, :granted_at, :if => :valid_type?

private
def valid_type?
  type != 1
end
Hauleth
  • 22,873
  • 4
  • 61
  • 112
  • Please can you explain a scenario where using private function is necessary or better instead of lambda/Proc or vice-versa...Just for understanding purpose.Thanks. – Huzaifa Saifuddin Jul 09 '18 at 12:12
  • Method can be public, this doesn’t require private method. – Hauleth Jul 09 '18 at 12:14
  • No .. What i meant was can you give example where in 1 case lambda/proc is better and in 1 case a function makes more sense. Thanks. – Huzaifa Saifuddin Jul 17 '18 at 07:47
  • 2
    @HuzaifaSaifuddin Functionally it makes no difference if you use a lambda or a private method. In almost every situation however I would prefer the private method for readability. Not only because the pure syntax is more readable, but because it forces you to think of a proper name for the expression. – trueunlessfalse Nov 24 '18 at 15:27
2

although the above mentioned ways are best practices but you can also make it simple like this:

validates_presence_of :state, :granted_at, :if => "type!=1"
Ahmad Hussain
  • 2,443
  • 20
  • 27
2

Building on the previous answers, you can also use a shorter "arrow" syntax

validates :state, :granted_at, presence: true, if: ->(o) { o.type != 1 }
coisnepe
  • 480
  • 8
  • 18