2

I would like to add some logic to my model to ensure there is a consistent string representation of a serial number in the database of devices. Below is an example of the sort of thing I'm thinking of: call a custom validation and do formatting on the data in the object before saving it to the database.

class Device < ActiveRecord::Base
  validates_presence_of :serialNumber
  validate :validate_sn
  def validate_sn
    if !serialNumber.nil? && serialNumber !~ /-/
      serialNumber = serialNumber.scan(/.{4}/).join('-')
    end
  end
end

I'm having two problems with this code. First, it will throw an error that says

NoMethodError: undefined method `scan' for nil:NilClass

on line 6, which is baffling to me. I can work around this by changing that line to:

sn = serialNumber; serialNumber = sn.scan(/.{4}/).join('-')

But if someone could explain why that works but the first doesn't I'd appreciate it. The real problem is that the data is saved without dashes (after that fix above is applied). Am I forgetting or misunderstanding something fundamental here? Does anyone have a better solution for this?

Thanks,

1
  • 5
    Slightly off the point but have you considered using a before_save filter instead of modifying the data in a validation? Commented Mar 23, 2011 at 17:27

2 Answers 2

3

Try

def validate_sn
  if !self.serialNumber.nil? && self.serialNumber !~ /-/
    self.serialNumber = self.serialNumber.scan(/.{4}/).join('-')
  end
end
Sign up to request clarification or add additional context in comments.

Comments

1

The first way doesn't work because you are using serialNumber in two different contexts.

In this line

if !serialNumber.nil? && serialNumber !~ /-/

you're using the method serialNumber, since this method doesn't exist, ruby will delegate to method_missing which will get the value from the @attributes hash.

But, in this line:

serialNumber = serialNumber.scan(/.{4}/).join('-')

you're using the serialNumber variable that you've just declared. This variable is of course nil. One way of achieving what you want is:

self.serialNumber = self.serialNumber.scan(/.{4}/).join('-')

But as another user already said, modifying the data in a validation is not a good practice. So, this code should be in a before_save filter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.