Cleaning Currency Values

1 view
Skip to first unread message

Bryce Thornton

unread,
Jan 15, 2008, 12:18:13 AM1/15/08
to Columbus Ruby Brigade
I'm trying to figure out how to clean up some form input for a
currency value. I'm using a decimal column to store the value and
have a basic text input box for the data entry.

My question: how can I sanitize this input data?

For instance, say the user enters "$115.25". Currently this is being
stored as "0.00" since ruby detects the dollar sign and strips
everything since it's not a numerical value. Similarly, "15,000.00"
is stored as "15.00" since the comma is detected as a non-numerical
value. It does this as soon as I call "update_attributes" in the
controller, so I don't think I can do much about in the model. By the
time before_validation fires it's already too late. I would assume
the same problem exists for ruby Integers, Floats, etc. So, what's
the "Rails Way" of handling this? Is there a way to clean the
parameters in the model before rails actually sets each attribute or
am I going to have to handle this in the controller?

Anthony Carlos

unread,
Jan 15, 2008, 12:56:06 AM1/15/08
to colum...@googlegroups.com
Hey Bryce,

I would use a regex to strip out anything that is not a digit or a decimal point:

input.gsub(/[^0-9.]/, '').to_f

I'm not sure of the "Rails Way," but it seems like a before filter might work well.

-Anthony
--


Anthony Carlos
Vice President
Digital Phenom
807 National Press Bldg
Washington DC 20045

Bryce Thornton

unread,
Jan 15, 2008, 1:12:37 AM1/15/08
to Columbus Ruby Brigade
Thanks Anthony. I was aiming to keep the logic in the model. What
I've done for now is just create a simple method in the model like
this:

def update_cleaned_attributes!(attributes)
if attributes[:salary_amount]
attributes[:salary_amount].gsub!(/[^0-9.]/, '')
end

self.update_attributes!(attributes)
end

I then just call this from my controller instead of
"update_attributes". It works, but feel free to chime in if there's a
way to do this better.

Thanks,
Bryce

Bryce Thornton

unread,
Jan 15, 2008, 1:27:03 AM1/15/08
to Columbus Ruby Brigade
Update.. I think this is a better solution:

def attributes=(attributes, guard_protected_attributes = true)
if attributes[:salary_amount]
attributes[:salary_amount].gsub!(/[^0-9.]/, '')
end

super(attributes, guard_protected_attributes)
end

It works without changing the way I typically add/update records.

Anthony Carlos

unread,
Jan 15, 2008, 2:03:16 AM1/15/08
to colum...@googlegroups.com
Bryce:

I guess I should not have said before _filter_. I meant a before callback. Perhaps the before_validation callback, which would then allow you to use your validation logic?

class Blah < AR::Base

before_validation :sanitize_money


def sanitize_money
  salary_amount.gsub!(/[^0-9.]/, '')
end


Sorry about the confusion... It's late!

-Anthony

Joe OBrien

unread,
Jan 15, 2008, 9:15:57 AM1/15/08
to colum...@googlegroups.com
Bryce,

I create 'getters' or 'setters' and then just use read_attribute,
write_attribute when necessary.

Here is one example. I want to take any of the following string for
gender: M, m, Male, Female, f, F .... etc..

So I take care of the logic before I store it. I also want to take
the chance to store it in a consistent way (translating M to Male).

#
# Custom writer to make sure we store the
# gender information consistently. We
# store: 'Male', 'Female', or 'Unknown'
#
def gender=(gender_string)
case gender_string
when /^[M|m](ale)*$/: write_attribute(:gender, 'Male')
when /^[F|f](emale)*$/: write_attribute(:gender, 'Female')
when /^[U|u](nknown)*$/: write_attribute(:gender, 'Unknown')
# Let the validations catch anything else.
else write_attribute(:gender, gender_string)
end
end

:gender is the field name in the database. This provides a hook if
you will that gives you access to the element before it's stored.
Validations will pick up _after_ this is run. Therefore, I allow
validations to kick in for the 'else' clause. I've combined this with
the following validator:

validates_inclusion_of :gender, :in => %w{ Male Female Unknown }

Hope this helps.

-Joe

-Joe
_______________
Joe O'Brien, artisan
EdgeCase
theedgecase.com

614/453-5527

Bryce Thornton

unread,
Jan 15, 2008, 9:29:09 AM1/15/08
to colum...@googlegroups.com
Joe, that is exactly what I was looking for.  Much cleaner than extending the entire "attributes=" method.

Thanks!
Bryce
Reply all
Reply to author
Forward
0 new messages