Rails money gem и конструктор форм

У меня проблема с формами и денежным драгоценным камнем.

Это моя проблема:

  1. Я создаю запись с полем «сумма» (сопоставленным с денежным объектом). Допустим, я ввожу 10 (долларов).
  2. Денежный камень конвертирует его в 1000 (центов)
  3. Я редактирую ту же запись, и форма предварительно заполняет поле суммы как 1000
  4. Если я сохраню запись, ничего не меняя, она преобразует 1000 (долларов) в 100000 (центов).

Как сделать так, чтобы предварительно заполненная сумма отображалась в долларах, а не в центах?

Редактировать:

Я попытался отредактировать _form.html следующим образом:

= f.text_field(:amount, :to_money)

и я получаю эту ошибку:

undefined method `merge' for :to_money:Symbol

person David    schedule 31.01.2011    source источник
comment
Это 1345. Я думаю, что форма извлекает сохраненное значение, не конвертируя его обратно в доллары.   -  person David    schedule 01.02.2011
comment
Так почему же 1000 преобразуется в 100, а не отображается 1000?! Что-то не так. Во-вторых (я не использовал денежный камень), но я подозреваю, что считыватель атрибутов для поля суммы не преобразует значение. Или, может быть, это нужно сделать вам, а не драгоценному камню? Некоторый код, который вы публикуете, поможет. Кроме того, проверьте загруженную запись и посмотрите, каково значение поля суммы.   -  person Zabba    schedule 01.02.2011
comment
Извините, это была опечатка. Он предварительно заполняется как 1000.   -  person David    schedule 01.02.2011
comment
Я думаю, вам нужно заполнить поле формы после того, как вы конвертируете его в доллары (возможно, используя поле to_money или что-то в этом роде)   -  person Zabba    schedule 01.02.2011
comment
Я пытался (см. мое редактирование), но форма html не распознает to_money   -  person David    schedule 01.02.2011


Ответы (4)


Учитывая миграцию следующим образом:

class CreateItems < ActiveRecord::Migration
  def self.up
    create_table :items do |t|
      t.integer :cents
      t.string :currency
      t.timestamps
    end
  end

  def self.down
    drop_table :items
  end
end

И модель следующим образом:

class Item < ActiveRecord::Base
  composed_of :amount,
    :class_name  => "Money",
    :mapping     => [%w(cents cents), %w(currency currency_as_string)],
    :constructor => Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
    :converter   => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't conver #{value.class} to Money") }
end

Тогда этот код формы должен работать отлично (я только что тестировал в Rails 3.0.3), правильно отображая и сохраняя сумму в долларах каждый раз, когда вы сохраняете/редактируете. (Это использует методы обновления/создания шаблона по умолчанию).

<%= form_for(@item) do |f| %>
  <div class="field">
    <%= f.label :amount %><br />
    <%= f.text_field :amount %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
person Dylan Markow    schedule 01.02.2011
comment
Ваш пример заставил меня понять проблему. В моей миграции у меня есть сумма t.integer, а в моей модели у меня есть составная часть: сумма. Это вызвало конфликт. Спасибо. - person David; 01.02.2011
comment
Спасибо за этот ответ. Просто и к вашему сведению для других - где написано [%w(cents cents)..., первые "центы" представляют ваш столбец в :items, а второй cents - это метод драгоценного камня. - person Patrick Connor; 16.04.2011

Если в вашей таблице есть несколько полей денег, и вы не можете назвать их все «центами».

class CreateItems < ActiveRecord::Migration
  def self.up
    create_table :items do |t|
      t.integer :purchase_price_cents
      t.string :currency
      t.timestamps
    end
  end

  def self.down
    drop_table :items
  end
end

который изменит вашу модель на

class Item < ActiveRecord::Base

  composed_of :purchase_price,
    :class_name  => "Money",
    :mapping     => [%w(purchase_price_cents cents), %w(currency currency_as_string)],
    :constructor => Proc.new { |purchase_price_cents, currency| Money.new(purchase_price_cents || 0, currency || Money.default_currency) },
    :converter   => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't convert #{value.class} to Money") }

end
person seehad    schedule 15.04.2011
comment
Очень хороший ответ. Приведение примера со столбцом Purchase_price_cents менее двусмысленно, потому что ясно, какой столбец является столбцом, а какой функцией. (%w(purchase_price_cents центов) против %w(центов центов) - person Christoph; 25.04.2012

Теперь вы можете напрямую редактировать монетизируемые поля (money-rails 1.3.0):

# add migration
add_column :products, :price, :price_cents

# set monetize for this field inside the model
class Product
  monetize :price_cents
end

# inside form use .price instead of .price_cents method
f.text_field :price

См. https://stackoverflow.com/a/30763084/46039.

person Brian Low    schedule 15.12.2015
comment
Более того, Money rails 1.11.0 теперь поддерживает t.monetize или add_monetize для миграции. - person tommyalvarez; 21.05.2018

монетизация и простая форма, шаги следующие:

  1. Миграция

add_monetize : таблица, : сумма

  1. Модель с проверкой

монетизация :amount_cents, allow_nil: true, численность: {больше_чем: 0}

  1. Параметры разрешения контроллера (не используйте здесь количество_центов)

params.require(:model).permit(:amount)

  1. простой ввод формы

когда он будет сохранен, он будет сохранен в центах в столбце amount_cents в db

person rail_engine    schedule 16.01.2019