I have validation on uniqueness and I want skipping certain value or values(for example 0000):
validates_uniqueness_of :gtin, :scope => [:user_id, :item_id]
I'm tried to use next construction, but she don't work:
validates_uniqueness_of :gtin, :scope => [:user_id, :item_id], :unless => Proc.new{|base_item| base_item.gtin == '0000'}
How I can skip certain value or values?
Thanks.
P.S. update!!!
did not see a manual migration, which change behaviour
using the :unless option is certainly the right way, but i think you get the whole object as proc argument so it should be
validates_uniqueness_of :gtin, :scope => [:user_id, :item_id], :unless => Proc.new{|obj| obj.gtin == '0000'}
Not sure if this is a gotcha or not. Is the value of gtin a string or an integer? It looks like what your doing should work, but if it's an integer you would want to change to:
validates :gtin, :uniqueness => {:scope => [:user_id, :item_id]}, :unless => Proc.new{|base_item| base_item.gtin == 0000}
I'm trying to do the same thing, and I think I know what's wrong. The problem is, the if or unless "base_item" object refers to the value you're checking the uniqueness for, not the prospective match object.
Maybe you really do mean to check the item you're validating (in which case I'm barking up the wrong tree), but it seems more natural in the uniqueness case to want to exclude certain matches. For instance, I have a field is_deleted, and I want to allow a uniqueness violation if the matching object has been deleted.
I can't find any way to reference the matching object that was found in the proc. You can accomplish this by making your own a custom validation function though. For instance, if you want to validate the uniqueness of 'name', you might try something like this:
validate :full_validation
def full_validation
matches = self.class.find_all_by_name(self.name).select {|match| match.id != self.id && match.is_deleted==false}
return (matches.size>0)
end
Related
In my Rails app college students with either #berkeley.edu or #uw.edu email addresses can register. I have the regex for validating both ready but since I need to check the email address the user enters to see which one it matches I think I need to create one regex, but I don't know how. Here are my two regex's:
berkeley_regex = /\A[\w+\-.]+#berkeley\.edu\z/i
uw_regex = /\A[\w+\-.]+#uw\.edu\z/i
And my validate:
validates :email, :presence => true, :uniqueness => true, :format => {:with => berkeley_regex}
Now, what would the regex to check against both but only match against one look like?
Can't you just validate against something like /\A[\w+\-.]+#(berkeley|uw)\.edu\z/i and be done with it? If you really need to later determine which it is, make a method that just checks the back part, or returns the match, or whatever...
First I think your regex should be changed from [\w+\-.] to [\w+\-\.]
The validation could be
validates :email, format: { with: "\A#{berkely_regex}|#{uw_regex}\z/i" }
but you'll need to remove the flags ( \A, \z, /i ) from the vartiables
New to rails so not sure what the best approach is here. I want to define a simple c++ style enum which can then be used as a custom type in my db. The enum can be simulated with an array or a custom module but how do I go about turning that into a custom type for my table?
Here's a pattern I follow in rails:
In my model class, I add a module to hold the possible values of the column. Then I put them into an array and define validation against the array of possible values.
Imagine I have a column/attribute called status and it can be three possible values. I'd do this:
class MyModel < ActiveRecord::Base
# This validates that status can't be null
validates :status, :presence => true
# Define a module with all possible values
module Status
IN_DEVELOPMENT = 'in development'
DISABLED = 'disabled'
ACTIVE = 'active'
end
# Now create an array of possible status values, and add a validation
STATUSES = [ Status::DISABLED, Status::ACTIVE, Status::IN_DEVELOPMENT]
validates :status, :inclusion => { :in => STATUSES, :message => "%{value} is not a valid status value" }
end
Have you considered using the built-in enumeration support in your database? Lots of common RDMBSes have enum support, such as Postgres (see http://www.postgresql.org/docs/9.1/static/datatype-enum.html) and MySQL (see http://dev.mysql.com/doc/refman/5.5/en/enum.html). With that, you can directly create the type in your data store and then use it via one of the ActiveRecord plugins (such as enum_type for Postgres: https://github.com/riscfuture/enum_type).
Alternatively, you could use something like active_enum to structure the enumeration as you described and store fields as integers in the database.
Depending on how you plan to utilize this enum type in your code I've found that using scopes accomplishes close to the same thing along with an enum type in the database to ensure only specific values are set.
Example:
scope :trial, :conditions => { :utype => 'TRIAL' }
scope :registered, :conditions => { :utype => 'REGISTERED' }
scope :active, :conditions => { :status => 'ACTIVE' }
scope :abuse, :conditions => { :status => 'ABUSE' }
I want to apply scope limiter in my custom validation
I have this Product Model
which has make,model,serial_number, vin as a attributes
Now I have a custom validation to check against vin if vin is not present to check for combination of make+model+serial_number uniqueness in database something like this
validate :combination_vin,:if => "vin.nil?"
def combination_vin
if Product.exists?(:make => make,:model => model,:serial_number => serial_number)
errors.add(:base,"The Combination of 'make+model+serial_number' already present")
end
end
I want to introduce a scope in this validator against user_id
Now I know I could easily write this to achieve same using
def combination_vin
if Product.exists?(:make => make,:model => model,:serial_number => serial_number,:user_id => user_id)
errors.add(:base,"The Combination of 'make+model+serial_number' already present")
end
end
But out of curiosity I was thinking is there a scope validator (something like {:scope => :user_id}) on custom validation
so that I dont have to pass that extra user_id in the exists? hash
Thanks
Try :
validate :combination_vin , :uniqueness => { :scope => :user_id } , :if => "vin.nil?"
We have an ActiveRecord model whose columns have some default values. It also has a validation condition such that, if the 'profile' property is set to a different value, then the default values are invalid.
What I'd like is to be able to determine whether the attributes have been set since they were set to the default so that I can reset them to new, valid values before validation.
Is this possible?
UPDATE: It's not clear what I mean, so I should give code examples.
The table is defined like this:
t.column :profile, :string
t.column :contact_by, :string, :default => "phone", :null => false
The validation is like this:
validate :validate_contact_by_for_profile1
def validate_contact_by
if (profile == "profile1") && (contact_by != "email")
errors.add(:contact_by, " must be 'email' for users in profile1")
end
end
So any time we do this:
u = User.new
u.profile => profile1
We end up with u being invalid. What I want to end up with is that the user's contact_by defaults to "phone", but if their profile is set to profile1, then it changes to "email", unless it has been set to something in the meantime. (Ideally this includes setting it to "phone")
EDITED ANSWER:
ok, don't know if I understood, but I'll try :P
you can writing a method to ovveride the profile= setter:
def profile=(value)
self.contact_by = 'email' if value == 'profile1'
super
end
this way works as you expect:
> n = YourModel.new
=> #<YourModel id: nil, profile: nil, contact_by: "phone", ...>
> n.profile = 'profile2'
=> "profile2"
> n.contact_by
=> "phone"
> n.profile = 'profile1'
=> "profile1"
> n.contact_by
=> "email"
as you can see, this way you get want you want. then you can do whatever validation you need .
hope this time helped ;-)
OLD ANSWER:
generally, you set default values during db migration. so when you try to save some data, the ActiveRecord model has blank data, then when saved on db, it gets default values.
according to this, you can play with validations in the model using something like this:
validates_presence_of :some_field, :if => Proc.new {|m| p.profile != <default value>}
alternatively, you can write a custom validation code, as private method, that will be called from validate:
validate :your_custom_validation_method, :if => Proc.new {|m| p.profile != <default value>}
btw I suggest you to look at ActiveRecord validations docs: http://guides.rails.info/active_record_validations_callbacks.html
I am trying to select an array, and check and see if any of the objects within the array are false. If any of them are false, I want an ultimate value of false returned.
If all of them are true, I want true returned..
Here's what I have..
validates_presence_of :email, :if => Proc.new { |user| user.organizations.find(:all).select {|org| org.contact_24} }
This unfortunately just returns the array.
How would you do it?
Perform the check in the DB, using the exists? method. This ensures all the calculations are done at the DB rather than the client code.
validates_presence_of :email,
:unless => Proc.new { organizations.exists?(:contact_24 => false)}
If you still insist on performing this at the client side then:
validates_presence_of :email,
:unless => Proc.new { organizations.any?{|o| o.contact_24 != true}}
OK, so your proc:
org.contact_24
Select will just return an array... So you need to return true if all org.contact_24 are true.
validates_presence_of :email, :if => Proc.new { |user| user.organizations.find(:all).collect {|org| org unless org.contact_24}.compact.blank? }
That'll build an array of org's that have contact_24 that are false. It then compacts the array, and returns true if it's blank.
So, it'll be false if any records aren't true.
I'd recommend moving the organizations.find(:all).collect {|org| org unless org.contact_24}.compact.blank? into a scope, so you'd end up with:
user.organizations.not_contacted_in_24_hours
Wow that is over complicating a simple task. How about
def some_func(arr)
!arr.include?(false)
end
Maybe I am missing something... but the question just asks how to return 'false' is an array includes 'false', and that's what this does.