RubyMoney / money-rails

Integration of RubyMoney - Money with Rails
MIT License
1.8k stars 387 forks source link

Thousand separator issue in monetized field validation #687

Closed RubenIgnacio closed 8 months ago

RubenIgnacio commented 9 months ago

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.

semmons99 commented 8 months ago

would you please submit a PR with a proposed fix (a failing test is a great first step)