This is such a dumb question that I feel like I must be missing something simple. I have a form with a quantity
field. People keep typing commas when they enter the quantity (for example, they type 12,000
to indicate twelve thousand) so I would like to strip out the commas before saving the quantity (12000
in the example) into an integer column in the database.
So far I have tried two methods. Overriding the setter method as suggested in this SO question
def quantity=(num)
num.gsub!(',', '') if num.is_a?(String)
self[:quantity] = num.to_i
end
This works in a sense. If I type 12,000
in the quantity field and submit the form, I get 12000
in the database. The problem is that it also bypasses all quantity
validations. No longer can I validate the presence of a value for quantity for example. This is not good.
I have also tried to use a before validation callback (instead of overriding the setter):
before_validation :sanitize_quantity
def sanitize_quantity
# Doesn't wok because quantity.to_i already called by this point.
end
This doesn't work because by the time the quantity has reached the callback method, Rails has already called to_i
on it. This means that 12,000
will be truncated to 12
by the time it reaches the callback. Once again, not good.
What else can I try aside from stripping the commas on the client-side?
As a final note, I am aware that this is essentially a dumb thing to do because certain countries use periods and commas in different ways. I still need to do it anyway.
If I understand your question correctly, you're trying to coerce strings into numbers. If so, you can just use an explicit cast like so:
validates :quantity, presence: true, numericality: true
def quantity=(num)
self[:quantity] = num.to_s.scan(/\b-?[\d.]+/).join.to_f
end
See see how this works, you can try the following at the console.
# String as input.
number = '12,956.05'
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05
# Float as input.
number = 12956.05
number.to_s.scan(/\b-?[\d.]+/).join.to_f
=> 12956.05
# Using an ActiveRecord object.
q = Quantity.new quantity: '12,956.05'
=> #<Quantity id: nil, quantity: 12956.05, created_at: nil, updated_at: nil>
q.save
=> true
I actually figured this out just as I was reading over my question.
The key is to use a virtual attribute.
class Job < ActiveRecord::Base
def flexible_quantity
quantity
end
def flexible_quantity=(quantity)
self.quantity = quantity.gsub(',', '') unless quantity.blank?
end
end
Then in the form, use the virtual attribute.
<%= f.text_field :flexible_quantity %>
Now validate the presence of the flexible_quantity value instead.
class Job < ActiveRecord::Base
validates :flexible_quantity, presence: true
# The cool this is that we can leave the numericality validation on the quantity field.
validates :quantity, presence: true, numericality: { only_integer: true }
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With