I have a Review model that has 3 validations that should only be run if the status
of the review is "submitted"
. Here is my current model...
class Review < ApplicationRecord
enum status: { pending: 0, submitted: 1 }
...
belongs_to :reviewable, polymorphic: true
belongs_to :user
validates :title, presence: true, length: { in: 5..50 }, if: -> { status == "submitted" }
validates :description, length: { in: 10..500 }, if: -> { status == "submitted" }
validates :stars, presence: true, inclusion: { in: (1..5) }, if: -> { status == "submitted" }
...
end
A new Review is generated with the status of "pending". I still need to validate that a reviewable
and user
are associated with the review when a new one is created (so, I can't skip validations all together in the create action)...but only need to validate title
, description
, and stars
when the user updates the review.
Is there a way to wrap the three validations (for title, description, and stars) in a conditional, so that it only runs the validations when a review is updated by the user (which changes the status
from pending
to submitted
)...instead of calling if: -> { status == "submitted" }
on all of them?
The first simplification is that you can use a symbol instead of an inline block:
validates :title, presence: true, length: { in: 5..50 }, if: :submitted?
validates :description, length: { in: 10..500 }, if: :submitted?
validates :stars, presence: true, inclusion: { in: (1..5) }, if: :submitted?
In general, you'd then define a method to match:
def submitted?
status == "submitted"
end
.. but you don't need to here, because enum
gives you such a method for free.
If you really want to squeeze it, there's a more obscure option:
with_options if: -> { status == "submitted" } do |x|
x.validates :title, presence: true, length: { in: 5..50 }
x.validates :description, length: { in: 10..500 }
x.validates :stars, presence: true, inclusion: { in: (1..5) }
end
(I switched back to the block because there's only one copy, though I'd still favour the if: :submitted?
form in this case.)
with_options
is not a particularly well-known, or widely used, method -- it's there, but I'd only suggest reaching for it in very unusual circumstances.