When validating a model with a monetized field retrieved from the database, a validation error is raised if the field is not set before the model is saved, regardless of whether the monetized field already has a value. For instance:
class Product < ActiveRecord::Base
monetize :price_cents, numericality: { less_than_or_equal_to: 1000 }
end
Consider a scenario where a product with a price of 120 USD is retrieved from the database, and when trying to save it, a validation error occurs:
product = Product.find(1) # <Product id: 1, price_cents: 12000, price_currency: "USD">
product.save # => false
# However, if the price is set before saving it, the operation succeeds
product.price = 120
product.save # => true
During the validation process, the MoneyValidator#validate_each method is invoked to verify whether raw_value.nil? && record.public_send(subunit_attr) is true. When this condition is true, raw_value is calculated as subunit_value.to_f / currency.subunit_to_unit, resulting in a float value.
Subsequently, when the generate_details method is called, it determines the currency's thousand separator in order to instantiate the Details object. For currencies that use a dot (.) as a thousand separator, the Details object, when passed to the normalize method, converts the raw_value to a string and removes the thousand separator.
This conversion process results in the original float value of 120.0 for raw_value being transformed into the string '120.0'. However, upon removal of the thousand separator, this string is interpreted as '1200', ultimately leading to a validation failure.
When validating a model with a monetized field retrieved from the database, a validation error is raised if the field is not set before the model is saved, regardless of whether the monetized field already has a value. For instance:
Consider a scenario where a product with a price of 120 USD is retrieved from the database, and when trying to save it, a validation error occurs:
During the validation process, the
MoneyValidator#validate_each
method is invoked to verify whetherraw_value.nil? && record.public_send(subunit_attr)
is true. When this condition is true,raw_value
is calculated assubunit_value.to_f / currency.subunit_to_unit
, resulting in a float value.Subsequently, when the
generate_details
method is called, it determines the currency's thousand separator in order to instantiate theDetails
object. For currencies that use a dot (.) as a thousand separator, theDetails
object, when passed to thenormalize
method, converts theraw_value
to a string and removes the thousand separator.This conversion process results in the original float value of
120.0
forraw_value
being transformed into the string'120.0'
. However, upon removal of the thousand separator, this string is interpreted as'1200'
, ultimately leading to a validation failure.