Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Way: Formatting Value Before Setting it in the Model?

I have form fields where the user enters in:

  • percents: 50.5%
  • money: $144.99
  • dates: Wednesday, Jan 12th, 2010

...

The percent and money type attributes are saved as decimal fields with ActiveRecord, and the dates are datetime or date fields.

It's easy to convert between formats in javascript, and you could theoretically convert them to the activerecord acceptable format onsubmit, but that's not a decent solution.

I would like to do something override the accessors in ActiveRecord so when they are set it converts them from any string to the appropriate format, but that's not the best either.

What I don't want is to have to run them through a separate processor object, which would require something like this in a controller:

def create
  # params == {:product => {:price => "$144.99", :date => "Wednesday, Jan 12, 2011", :percent => "12.9%"}}
  formatted_params = Product.format_params(params[:product])
  # format_params == {:product => {:price => 144.99, :date => Wed, 12 Jan 2011, :percent => 12.90}}
  @product = Product.new(format_params)
  @product.save
  # ...
end

I would like for it to be completely transparent. Where is the hook in ActiveRecord so I can do this the Rails Way?

Update

I am just doing this for now: https://gist.github.com/727494

class Product < ActiveRecord::Base
  format :price, :except => /\$/
end

product = Product.new(:price => "$199.99")
product.price #=> #<BigDecimal:10b001ef8,'0.19999E3',18(18)>
like image 810
Lance Avatar asked Dec 03 '10 19:12

Lance


3 Answers

You could override the setter or getter.

Overriding the setter:

class Product < ActiveRecord::Base
  def price=(price)
    self[:price] = price.to_s.gsub(/[^0-9\.]/, '')
  end
end

Overriding the getter:

class Product < ActiveRecord::Base
  def price
    self[:price].to_s.gsub(/[^0-9\.]/, ''))
  end
end

The difference is that the latter method still stores anything the user entered, but retrieves it formatted, while the first one, stores the formatted version.

These methods will be used when you call Product.new(...) or update_attributes, etc...

like image 108
iain Avatar answered Nov 20 '22 05:11

iain


You can use a before validation hook to normalize out your params such as before_validation

class Product < ActiveRecord::Base

     before_validation :format_params


      .....


     def format_params
        self.price = price.gsub(/[^0-9\.]/, "")
        ....
     end
like image 37
Doon Avatar answered Nov 20 '22 04:11

Doon


Use monetize gem for parsing numbers.

Example

Monetize.parse(val).amount
like image 24
xpepermint Avatar answered Nov 20 '22 03:11

xpepermint