Transforming arguments to find_by

I have a model that contains a “normalized” 10-digit US phone
number.

I’d like my find_by_phone_number method (and its variants) to be able
to take unnormalized forms (eg, +1(555)555-5555). Is there a way for
me to modify the dynamic find methods to perform my
PhoneNumberHelper::normalize on the argument, without having to
replace all of the dynamic methods with my own versions?

Thanks,
Andrew

On 13 February 2010 07:59, acreadinglist [email protected] wrote:

without having to
replace all of the dynamic methods with my own versions?

Essentially, I’d say “no”.
There wouldn’t be an easy way for the dynamic find_by_xyz to normalize
your data, as it wouldn’t know which “helper” methods to call,

The easiest solution is to create a find_by_phone_number method of
your own in your model, in which you do your normalizing, and then do
a find with conditions.

But it you want to delve into the Rails source code and monkey-patch
the method_missing? method that does the magic “find bys” (I can’t
recall where it would be off the top of my head), that might be your
best route if you really want it all done magically (personally, I
prefer custom code like that in the models, where I know where to find
it - especially when I’m looking again in six months and can’t
remember how everything hangs together!)

Just as an aside, why don’t you do the normalizing before you call the
find_by? … pass in the normalized value as normal?

Thanks for the response Michael.

I agree, better to have the code in the models than monkey patching
Rails.

And to that end, I am doing what you asked about last - normalizing
before passing it in. But it just feels like the wrong solution. It
forces me to put normalization calls in a bunch of places in the code;
if I could normalize in the find automatically, it would only be in
one place in the code, and nobody (just me for now, but who knows
eventually) would have to remember to normalize a number before
passing it in.

On 19 February 2010 06:28, acreadinglist [email protected] wrote:

eventually) would have to remember to normalize a number before
passing it in.

I like to follow the pattern of fixing one, and only one, problem at a
time; first, get the finder working, then move onto the next task.
In this case the next task is to dry up all that normalization…

so you’ve got something like this duplicated in lots of controllers:

controller

phone_number = phone_number_normalize_method(params[:phone_number])
@people = Person.find_by_phone_number(phone_number)

(hopefully the “phone_number_normalize_method” is somewhere shared,
not copied into every controller… :wink:

so to save having to remember to normalize, extract that pattern as a
class method on Person; so the process becomes:

controller

@people =
Person.normalize_and_find_by_phone_number(params[:phone_number])

Person model

def self.normalize_and_find_by_phone_number(phone_number)
Person.find_by_phone_number(phone_number_normalize_method(phone_number))
end