So I have a form where users can input a price. I\'m trying to make a before_validation that normalizes the data, clipping the $ if the user puts it.
before_val
My soluction colum price type decimal
t.decimal :price, precision: 12, scale: 6
# app/concern/sanitize_fields.rb
module SanitizeFields
extend ActiveSupport::Concern
def clear_decimal(field)
return (field.to_s.gsub(/[^\d]/, '').to_d / 100.to_d) unless field.blank?
end
def clear_integer(field)
field.to_s.strip.gsub(/[^\d]/, '') unless field.blank?
end
# module ClassMethods
# def filter(filtering_params)
# results = self.where(nil)
# filtering_params.each do |key, value|
# results = results.public_send(key, value) if value.present?
# end
# results
# end
#
# #use
# #def index
# # @products = Product.filter(params.slice(:status, :location, :starts_with))
# #end
#
# end
end
#app/controllers/products_controller.rb
include SanitizeFields
params[:product][:price] = clear_decimal(params[:product][:price])
I would define a virtual attribute and do my manipulation there allowing you to format and modify both the getter and setter at will:
class Model < ActiveRecord::Base
def foo_price=(price)
self.price = price... #=> Mods to string here
end
def foo_price
"$#{price}"
end
You also might want to note that:
"$50.00".gsub(/\D/, '').to_i #=> 5000
One way is to override the mechanism on the model that sets the price, like this:
def price=(val)
write_attribute :price, val.to_s.gsub(/\D/, '').to_i
end
So when you do @model.price = whatever
, it will go to this method instead of the rails default attribute writer. Then you can convert the number and use write_attribute
to do the actual writing (you have to do it this way because the standard price=
is now this method!).
I like this method best, but for reference another way to do it is in your controller before assigning it to the model. The parameter comes in as a string, but the model is converting that string to a number, so work with the parameter directly. Something like this (just adapt it to your controller code):
def create
@model = Model.new(params[:model])
@model.price = params[:model][:price].gsub(/\D/, '').to_i
@model.save
end
For either solution, remove that before_validation
.