我有an application来处理货币输入。但是,如果您在美国,则可以输入12,345.67
的数字;在法国,它可能是12.345,67
。
在Rails中,有一种简单的方法可以使货币条目适应区域设置吗?
请注意,我不是在寻找货币的显示(ala number_to_currency
),我正在寻找某人输入货币字符串,并将其转换为小数。
答案 0 :(得分:11)
你可以试一试:
def string_to_float(string)
string.gsub!(/[^\d.,]/,'') # Replace all Currency Symbols, Letters and -- from the string
if string =~ /^.*[\.,]\d{1}$/ # If string ends in a single digit (e.g. ,2)
string = string + "0" # make it ,20 in order for the result to be in "cents"
end
unless string =~ /^.*[\.,]\d{2}$/ # If does not end in ,00 / .00 then
string = string + "00" # add trailing 00 to turn it into cents
end
string.gsub!(/[\.,]/,'') # Replace all (.) and (,) so the string result becomes in "cents"
string.to_f / 100 # Let to_float do the rest
end
测试案例:
describe Currency do
it "should mix and match" do
Currency.string_to_float("$ 1,000.50").should eql(1000.50)
Currency.string_to_float("€ 1.000,50").should eql(1000.50)
Currency.string_to_float("€ 1.000,--").should eql(1000.to_f)
Currency.string_to_float("$ 1,000.--").should eql(1000.to_f)
end
it "should strip the € sign" do
Currency.string_to_float("€1").should eql(1.to_f)
end
it "should strip the $ sign" do
Currency.string_to_float("$1").should eql(1.to_f)
end
it "should strip letter characters" do
Currency.string_to_float("a123bc2").should eql(1232.to_f)
end
it "should strip - and --" do
Currency.string_to_float("100,-").should eql(100.to_f)
Currency.string_to_float("100,--").should eql(100.to_f)
end
it "should convert the , as delimitor to a ." do
Currency.string_to_float("100,10").should eql(100.10)
end
it "should convert ignore , and . as separators" do
Currency.string_to_float("1.000,10").should eql(1000.10)
Currency.string_to_float("1,000.10").should eql(1000.10)
end
it "should be generous if you make a type in the last '0' digit" do
Currency.string_to_float("123,2").should eql(123.2)
end
答案 1 :(得分:5)
我们写了这个:
class String
def safe_parse
self.gsub(I18n.t("number.currency.format.unit"), '').gsub(I18n.t("number.currency.format.delimiter"), '').gsub(I18n.t("number.currency.format.separator"), '.').to_f
end
end
当然,您必须在使用之前设置I18n.locale。它目前只将字符串转换为已设置的语言环境的浮点数。 (在我们的例子中,如果用户在法国网站上,我们希望货币金额文本只包含符合法国语言环境的符号和格式。)
答案 2 :(得分:4)
您需要清理输入,以便用户可以输入他们想要的任何内容,并且您将获得一致的内容以存储在您的数据库中。假设您的模型名为“DoughEntry”,您的属性为“amount”,并将其存储为整数。
这是一个将字符串输入转换为美分的方法(如果字符串以分隔符后面的两位数结尾,则假定为美分)。您可能希望更聪明,但这是概念:
def convert_to_cents(input)
if input =~ /^.*[\.,]\d{2}$/
input.gsub(/[^\d-]/,'').to_i
else
"#{input.gsub(/[^\d-]/,'')}00".to_i
end
end
>> convert_to_cents "12,345"
=> 1234500
>> convert_to_cents "12.345,67"
=> 1234567
>> convert_to_cents "$12.345,67"
=> 1234567
然后覆盖默认的“金额”访问者,通过该方法传递:
class DoughEntry << ActiveRecord::Base
def amount=(input)
write_attribute(:amount, convert_to_cents(input))
end
protected
def convert_to_cents(input)
if input =~ /^.*[\.,]\d{2}$/
input.gsub(/[^\d-]/,'').to_i
else
"#{input.gsub(/[^\d-]/,'')}00".to_i
end
end
end
现在你将美分存储在数据库中。雷达有正确的想法将它拉回来。
答案 3 :(得分:2)
添
您可以尝试使用'aggregation' feature,并结合授权类。我会做类似的事情:
class Product
composed_of :balance,
:class_name => "Money",
:mapping => %w(amount)
end
class Money < SimpleDelegator.new
include Comparable
attr_reader :amount
def initialize(amount)
@amount = Money.special_transform(amount)
super(@amount)
end
def self.special_transform(amount)
# your special convesion function here
end
def to_s
nummber_to_currency @amount
end
end
通过这种方式,您可以直接指定:
Product.update_attributes(:price => '12.244,6')
或
Product.update_attributes(:price => '12,244.6')
优点是您不必在控制器/视图上修改任何。
答案 4 :(得分:2)
使用内置I18n中的translations for numbers应该允许您以一种格式(1234.56)输入价格,然后使用I18n将它们带回number_to_currency
以自动打印出来正确的语言环境。
当然,您必须使用I18n.locale
设置before_filter
,请查看I18n guide第2.3节。