How to validate against the object "in memory" versus the stored object in the database
The following code works just fine on creating "channels" that have an address like emails or phones.
class Channel < ActiveRecord::Base
belongs_to :contact
belongs_to :mechanism
validates_uniqueness_of :address
validates_format_of :address, :with => /@/i,
:if => :address_is_email?
validates_format_of :address, :with => /\d\d\d\d\d\d\d\d\d\d/,
:if => :address_is_phone?
def before_validation
self.address = address.gsub(/[^0-9]/, "") if mechanism.designation == "sms"
end
def address_is_email?
mechanism.designation == "smtp"
end
def address_is_phone?
mechanism.designation == 开发者_StackOverflow社区"sms"
end
end
Like so:
>> c = Channel.create(:mechanism_id => 1, :address => 'something@someplace.com')
=> #<Channel id: 17, created_at: "2010-12-02 15:00:59", updated_at: "2010-12-02 15:00:59", mechanism_id: 1, contact_id: nil, address: "something@someplace.com", enabled: nil, time_window_id: nil>
>> c.save
=> true
However, if I try to change the format from one to the other after the fact, it will fail.
>> c.update_attributes(:address => '888.555.1212', :mechanism_id => 2)
=> false
>> c.save
=> false
I'm guessing that this is because the validates_format_of is going through the address_is_*? function, and reading against the format that's stored in the database (or in memory already), and NOT against the value I'm feeding it. How would I test against the new value that I'm passing (somehow) to the class when I try to do the update_attributes? The only thing I can see to do, given the code above, is delete the channel and create a new one with the different format.
Your problem is with this line:
validates_format_of :address, :with => /\d\d\d\d\d\d\d\d\d\d/,
:if => :address_is_phone?
The regular expression is expecting 10 digits, with nothing in between! If you want dots, like your example above, do it like this:
validates_format_of :address, :with => /\d\d\d\.\d\d\d\.\d\d\d\d/,
:if => :address_is_phone?
And of course, you can get as complex as you want from there. I hope this helps!
PS: This is a shorter, easier to read version:
validates_format_of :address, :with => /\d{3}\.\d{3}\.\d{4}/,
:if => :address_is_phone?
精彩评论