Validate presence of one field or another or both(OR) - ruby-on-rails

So I'm looking at this link but I'm wondering how to do an 'OR' instead of an 'XOR'. Does anyone know how to do this? I am trying to do this using Rails 3.

There is short option for Rails 4 (not sure about Rails 3) :
validates :email, presence: { if: -> { username.blank? } }
validates :username, presence: { if: -> { email.blank? } }

I figured it out. all you have to change is the ^ to &&
private
def time_or_money
if time.blank? && money.blank?
errors[:base] << "Specify Time, Money or Both."
end
end

Related

Conditional Validation for Serialized Array

How can I create a validation where committed presence needs to be true only if the challenge's category is habit?
class Challenge < ActiveRecord::Base
CATEGORY = ['goal', 'habit']
serialize :committed, Array
validates :committed, presence: true, if: :habit # I also tried with 'habit' & 'Habit'
end
Since your category is called 'habit' (note, it is not 'Habit'), the validation would look as follows:
validates :committed, presence: true, if: ->(c) { c.category == 'habit' }
As a sidenote: I do not think your scopes will work, unless you have a column called categories in your challenges table.
Thus, if your intention was to select challenges, which have category 'habit', the scope would look as follows:
scope :habit, -> { where(category: 'habit') }
EDIT
As per discussion in comments, if you want committed to be nil instead of [""] when nothing is there, add custom validation:
validate :committed_content
private
def committed_content
self.committed = nil if committed.empty? || committed.all?(&:blank?)
true
end
validates :committed, presence: true, :if => lambda { |c| c.category == 'Habit' }
You can have a method and use it like this:
validates :committed, presence: true, if: :habit?
def habit?
self.category == 'habit'
end

ActiveModel::Validation Any of 3 fields

I have 3 fields in my Model and i need at least one of them to be present - how can do this using inbuilt validations?
Create a custom validation:
validate :one_of_three
def one_of_three
errors.add(:base, 'Must have one of foo, bar or wee') unless foo || bar || wee
end
Try the following.
validate :attributes_presence
def attributes_presence
errors.add(:base, 'At least one attribute must be present') if attr1.blank? && attr2.blank? && attr3.blank?
end
There is a way to conditionally validate the presence of one attribute depending on presence of another:
validates :attr_1,
presence: true,
if: ->(model) { model.attr_2.blank? && model.attr_3.blank? }
validates :attr_2,
presence: true,
if: ->(model) { model.attr_1.blank? && model.attr_3.blank? }
validates :attr_3,
presence: true,
if: ->(model) { model.attr_1.blank? && model.attr_2.blank? }

How can I use a custom validation with shoulda matchers?

I have been unable to wrap my head around how to get these tests back to green.
Model
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: true
validates :zip, presence: true, format: { with: VALID_ZIP_REGEX }
validates_numericality_of :puzzle_pieces, only_integer: true
Spec
it { should validate_presence_of(:email) }
it { should validate_uniqueness_of(:email) }
it { should allow_value('john.doe#example.com', 'alice#yahoo.ca').for(:email) }
it { should_not allow_value('john2example.com', 'john#examplecom').for(:email) }
it { should validate_presence_of(:zip) }
it { should allow_value('35124', '35124-1234').for(:zip) }
it { should_not allow_value('5124', '35124-12345').for(:zip) }
it { should validate_numericality_of(:puzzle_pieces).only_integer }
The above tests pass until I add this custom validation.
Custom Validator
class PiecesValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value > 0 && value <= Puzzle.remaining
record.errors[attribute] << (options[:message] || "Puzzle pieces must be between 1 and #{Puzzle.remaining}")
end
end
end
Model
validates :puzzle_pieces, pieces: true
Spec
it "does not allow a negative number of puzzle pieces to be saved" do
order = build(:order, puzzle_pieces: -1)
expect(order).to be_invalid
end
That last test passes, but all of my shoulda tests then fail with the same error
NoMethodError:
undefined method `>' for nil:NilClass
I am not understanding how to fix this. It seems that the shoulda tests operate in isolation just fine. But then they all blow up when the custom validation is added in.
Any help pushing me towards understanding this would be greatly appreciated!
Your problem is that your validation is not expecting value to be nil. Change your method to:
class PiecesValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value && value > 0 && value <= Puzzle.remaining
record.errors[attribute] << (options[:message] || "Puzzle pieces must be between 1 and #{Puzzle.remaining}")
end
end
end
This will not add an error if validated field is blank. However, what you are trying to do can be achieved using standard rails validators:
validates :puzzle_pieces, numericality: { only_integer: true, less_then: Puzzle.remaining, greater_then: 0 }

how to pass proc to conditions in validates

How can I write validation for barcode to be unique for all users where is_deleted is false and same chain?
validates :barcode, uniqueness: { conditions: -> { |record| where(is_deleted: false, chain_id: record.chain_id) } }, if: proc { |u| u.barcode.present? }
what is wrong here?
Thanks.
upd. There can be two users with same barcode with same chain_id, if one of them or both have :is_deleted => true
Rails validation have if and unless parameters which allow you to add conditions, you used it to check barcode presence properly, but you can extend it for is_deleted as well.
As to chain id, I understand that you are interested in scoping.
In your case that would be
validates :barcode, uniqueness: { scope: [:chain_id] }, if: proc { |u| u.barcode.present? && w.is_deleted.false? }
validates :barcode, uniqueness: { scope: :chain_id, conditions: ->{ where(is_deleted: false) } }, if: proc { |u| u.barcode.present? && u.active? }
I came up with a solution.
Thanks and sorry, its late here and head is not working as expected :)

Hide password_digest error message in JSON output

I'm building a simple JSON API using the rails-api gem.
models/user.rb:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation
validates :email, presence: true, uniqueness: { case_sensitive: false }, format: { with: /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i }
validates :password, presence: { on: :create }, length: { minimum: 6 }
end
When I try to sign up without a password this is the JSON output I get:
{
"errors": {
"password_digest": [
"can't be blank"
],
"password": [
"can't be blank",
"is too short (minimum is 6 characters)"
]
}
}
Is it possible to hide the error message for password_digest? I'm returning the #user object with respond_with in the controller.
I've tried the following but no luck (it just duplicates the error "can't be blank"):
validates :password_digest, presence: false
#freemanoid: I tried your code, and it didn't work. But it gave me some hints. Thanks! This is what worked for me:
models/user.rb
after_validation { self.errors.messages.delete(:password_digest) }
You can manually delete this message in json handler in User model. Smth like:
class User < ActiveRecord::Base
def as_json(options = {})
self.errors.messages.delete('password_digest')
super(options)
end
end

Resources