【问题标题】:Rails money gem and form builderRails 金钱宝石和表单生成器
【发布时间】:2011-01-31 22:20:37
【问题描述】:

我遇到了表单和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

【问题讨论】:

  • 现在是 1345。我认为表单正在检索存储的价值,而不会将其转换回美元。
  • 那么为什么 1,000 被转换为 100 而不显示 1,000?!那里出了点问题。其次(我没有使用货币宝石),但我怀疑金额字段的属性读取器没有转换值。或者这可能需要由您而不是宝石来完成?您发布的一些代码会有所帮助。另外,检查加载的记录,看看金额字段的值是多少。
  • 抱歉打错了。它预填充为 1000。
  • 我猜你需要在将其转换为美元后填充表单字段(可能使用to_money 字段或类似的东西)
  • 我尝试过(查看我的编辑),但表单 html 无法识别 to_money

标签: ruby-on-rails forms rubygems currency formbuilder


【解决方案1】:

假设迁移如下:

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 %>

【讨论】:

  • 你的例子让我发现了问题。在我的迁移中,我有 t.integer 数量,在我的模型中,我有 composition_of :amount。这引起了冲突。谢谢。
  • 感谢您的回答。仅供参考 - 写[%w(cents cents)...的地方,第一个'cents'代表你在:items中的列,第二个cents是gem的一个方法。
【解决方案2】:

如果您的表格中有多个货币字段,并且您不能将它们全部命名为“美分”。

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

【讨论】:

  • 很好的答案。举一个带有“purchase_price_cents”列的例子就不会那么模棱两可了,因为它清楚地表明了哪一个是列,哪一个是函数。 (%w(purchase_price_cents cents) vs. %w(cents cents)
【解决方案3】:

您现在可以直接编辑获利字段(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

【讨论】:

  • 更好的是,Money rails 1.11.0 现在支持 t.monetize 或 add_monetize 进行迁移
【解决方案4】:

货币化和简单的形式,步骤如下:

  1. 迁移

add_monetize :table, :amount

  1. 带有验证的模型

货币化:amount_cents,allow_nil: true,numerity: {greater_than: 0}

  1. 控制器许可参数(此处不要使用 amount_cents)

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

  1. 简单的表单输入

当它被保存时,它将以美分保存在 db 的 amount_cents 列中

【讨论】:

    猜你喜欢
    • 2011-06-15
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多