Rails - Validation :if one condition is true
Asked Answered
W

5

38

On Rails 5.

I have an Order model with a description attribute. I only want to validate it's presence if one of two conditions is met: if the current step is equal to the first step OR if require_validation is equal to true.

I can easily validate based on one condition like this:

validates :description, presence: true, if: :first_step?

def first_step?
 current_step == steps.first
end

but I am not sure how to go about adding another condition and validating if one or the other is true.

something like:

validates :description, presence: true, if: :first_step? || :require_validation

Thanks!

Wadewadell answered 27/2, 2017 at 20:27 Comment(0)
A
78

You can use a lambda for the if: clause and do an or condition.

validates :description, presence: true, if: -> {current_step == steps.first || require_validation}
Adne answered 27/2, 2017 at 20:36 Comment(1)
Beautiful solution.Insect
D
16

Can you just wrap it in one method? According to the docs

:if - Specifies a method, proc or string to call to determine if the validation should occur (e.g. if: :allow_validation, or if: Proc.new { |user| user.signup_step > 2 }). The method, proc or string should return or evaluate to a true or false value.

validates :description, presence: true, if: :some_validation_check

def some_validation_check
    first_step? || require_validation
end
Deherrera answered 27/2, 2017 at 20:33 Comment(0)
I
3

You can pass a lambda to be evaluated as the if condition.

Try:

validates :description, presence: true, if: -> { first_step? || require_validation }
Imminent answered 27/2, 2017 at 20:38 Comment(3)
Isn't that a lambda? A block would be: validates :description, presence: true, if: { first_step? || require_validation }Distracted
Ah, you are right. I should have said "You can pass a lambda".Imminent
:) A block also works though. Rails just converts it to a proc or lambda (I forget what) before using it.Distracted
C
1

If you don't want to add one method as Jared say then you can try use lambda

validates :description, presence: true, if: ->{ first_step? || require_validation }
Concepcionconcept answered 27/2, 2017 at 20:36 Comment(0)
D
1

If you have a lot case , you can design for validates

validates_presence_of :price_tech_fee, if: :price_tech_fee_require?, :message => :required

validates_presence_of :percentage_tech_fee, if: :percentage_tech_fee_require?, :message => :required

def percentage_tech_fee_require?
    is_active? && is_transaction_percentage? && is_premium?
  end

def is_active?
  !self.is_deleted && self.is_active
end

def is_transaction_percentage?
 self.is_per_transaction && self.is_percentage
end

def is_premium?
  ....
end
Dirty answered 11/11, 2019 at 18:12 Comment(1)
Convention says that you shouldn't define a method that is called "is_,,," if it should return a boolean value. Just use "?" at the end (like you did).Hadfield

© 2022 - 2024 — McMap. All rights reserved.