处理Ruby on Rails中的国际货币输入

我有一个处理货币输入的应用程序 。 但是,如果你在美国,你可以输入一个12,345.67的数字; 在法国,它可能是12.345,67

在Rails中,有一种简单的方法可以使货币条目适应区域设置吗?

请注意,我不是在寻找货币的显示(ala number_to_currency ),我正在寻找与某人输入货币字符串并将其转换为小数的人。

你可以试一试:

  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 (eg ,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 

我们写了这个:

 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。 它目前只将字符串转换为已设置的语言环境的浮点数。 (在我们的例子中,如果用户在法国网站上,我们希望货币金额文本只包含与法国语言环境相关的符号和格式)。

您需要清理输入,以便用户可以输入他们想要的任何内容,并且您将获得一致的内容以存储在您的数据库中。 假设您的模型名为“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 

然后覆盖默认的“amount”访问器,通过该方法传递:

 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 

现在你将美分存储在数据库中。 雷达有正确的想法将它拉回来。

蒂姆

您可以尝试使用“聚合”function ,并结合委托类。 我会做的事情如下:

 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') 

优点是您不必修改控制器/视图上的任何内容

使用内置I18n中的数字翻译应该允许您以一种格式(1234.56)输入价格,然后使用I18n将它们与number_to_currency一起退出,以使它们以正确的语言环境自动打印出来。

当然你必须使用before_filter设置I18n.locale ,查看I18n指南 ,2.3节。