I have a Question class:
class Question < ActiveRecord::Base attr_accessible :user_id, :created_on validates_uniqueness_of :created_on, :scope => :user_id end
A given user can only create a single question per day, so I want to force uniqueness in the database via a unique index and the Question class via validates_uniqueness_of.
The trouble I'm running into is that I only want that constraint for non-admin users. So admins can create as many questions per day as they want. Any ideas for how to achieve that elegantly?
So remember folks, validates is for Rails validators (and custom validator classes ending with Validator if that's what you're into), and validate is for your custom validator methods.
Rails built-in Validation MethodsValidates whether associated objects are all valid themselves. Work with any kind of association. It validates whether a user has entered matching information like password or email in second entry field. Validates each attribute against a block.
A very common way to skip validation is by keeping the value for immediate attribute as 'true' for the UIComponents. Immediate attribute allow processing of components to move up to the Apply Request Values phase of the lifecycle. scenario: While canceling a specific action, system should not perform the validation.
You can make a validation conditional by passing either a simple string of Ruby to be executed, a Proc, or a method name as a symbol as a value to either :if
or :unless
in the options for your validation. Here are some examples:
Prior to Rails version 5.2 you could pass a string:
# using a string: validates :name, uniqueness: true, if: 'name.present?'
From 5.2 onwards, strings are no longer supported, leaving you the following options:
# using a Proc: validates :email, presence: true, if: Proc.new { |user| user.approved? } # using a Lambda (a type of proc ... and a good replacement for deprecated strings): validates :email, presence: true, if: -> { name.present? } # using a symbol to call a method: validates :address, presence: true, if: :some_complex_condition def some_complex_condition true # do your checking and return true or false end
In your case, you could do something like this:
class Question < ActiveRecord::Base attr_accessible :user_id, :created_on validates_uniqueness_of :created_on, :scope => :user_id, unless: Proc.new { |question| question.user.is_admin? } end
Have a look at the conditional validation section on the rails guides for more details: http://edgeguides.rubyonrails.org/active_record_validations.html#conditional-validation
The only way I know of to guarantee uniqueness is through the database (e.g. a unique index). All Rails-only based approaches involve race conditions. Given your constraints, I would think the easiest thing would be to establish a separate, uniquely indexed column containing a combination of the day and user id which you'd leave null
for admins.
As for validates_uniqueness_of
, you can restrict validation to non-admins through use of an if
or unless
option, as discussed in http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With