I have a model named Widget
that has a single monetized attribute named advance
.
Each instance of a Widget
may have an advance
attribute that stores a unique currency and amount.
Despite setting up everything based on the gem documentation, and having the ability to switch between the default currency USD
and switching to other currencies, such as JPY
, CSD
, CNY
, switching to EUR
throws errors and prevents updating the advance_currency
and advance_cents
values.
ruby "3.1.2"
gem "rails", "7.0.2.3"
gem "money-rails", "1.15.0"
Money.locale_backend = :currency
MoneyRails.configure do |config|
config.default_currency = :usd
config.include_validations = true
config.rounding_mode = BigDecimal::ROUND_HALF_UP
end
create_table :widgets, force: :cascade do |t|
...
t.monetize :advance, amount: { limit: 8 }
end
create_table "widgets", force: :cascade do |t|
...
t.bigint "advance_cents", default: 0, null: false
t.string "advance_currency", default: "USD", null: false
...
end
class Widget < ApplicationRecord
...
monetize :advance_cents, with_model_currency: :advance_currency
...
end
<div class="form-floating">
<%= select_tag("advance_currency", options_for_select(CurrencyTypes.options_for_select, @instance.advance_currency), prompt: "Select a currency", class: "form-select") %>
<label for="advance_currency" class="form-label">Advance Currency</label>
</div>
<div class="form-floating">
<input type="number" step="any" class="form-control" id="advance" name="advance" value="<%= number_to_currency(@instance.advance, unit: "", separator: ".") %>">
<label for="advance" class="form-label">Advance Amount</label>
</div>
def update
instance = controller_class.find(params[:id])
instance.update(update_params)
...
end
private
def update_params
params.permit(
...
:advance,
:advance_currency,
...
)
end
#<ActionController::Parameters {
...
"advance_currency"=>"JPY",
"advance"=>"987.65",
} permitted: false>
> instance.update(update_params)
> instance.save
true
> instance.errors
#<ActiveModel::Errors []>
#<ActionController::Parameters {
...
"advance_currency"=>"EUR",
"advance"=>"123.45",
} permitted: false>
> instance.update(update_params)
> instance.save
false
> instance.errors
#<ActiveModel::Errors [#<ActiveModel::Error attribute=advance, type=invalid_currency, options={:thousands=>".", :decimal=>",", :currency=>"123.45", :attribute=>"Advance"}>]>
What doesn't make any sense is that when switching to Euro as the currency, the advance amount seems to be entered into the currency
value instead of EUR
.
I have no idea why one currency throws off the money-rails gem operations while the others work correctly.
It seems like the use of the number
type input is the problem.
You can only submit values in Euro with the 123.456,78
format instead of 123,456.78
for the other currencies.
Since a comma is not allowed in the number
input type, you must switch to a type of text
<div class="form-floating">
<input type="number" class="form-control" id="advance" name="advance" value="<%= @instance.advance %>">
<label for="advance" class="form-label">Advance Amount</label>
</div>
<div class="form-floating">
<input type="text" class="form-control" id="advance" name="advance" value="<%= @instance.advance %>">
<label for="advance" class="form-label">Advance Amount</label>
</div>