No PHP, uma função muito usada é number_format, mas no Ruby não temos nada assim nativamente. O Rails implementa sua própria versão com o helper number_to_currency, que satisfaz totalmente minhas necessidades. O problema é que ele só está disponível na view e, sendo assim, você não consegue utilizá-lo nem no modelo, nem no controller.
Para resolver isto, estendi algumas classes de modo que isso esteja disponível para qualquer instância de números (Fixnum, Bignum ou Float). Adicionalmente, um método to_number foi adicionado aos objetos da classe String, convertendo valores como 150.00 ou 150,00 para números do tipo Float.
module Currency
BRL = {:delimiter => ".", :separator => ",", :unit => "R$", :precision => 2, :position => "before"}
USD = {:delimiter => ',', :separator => ".", :unit => "US$", :precision => 2, :position => "before"}
DEFAULT = USD.merge(:unit => "$")
module String
def to_number(options={})
return self.gsub(/,/, '.').to_f if self.numeric?
nil
end
def numeric?
self =~ /^(\+|-)?[0-9]+((\.|,)[0-9]+)?$/ ? true : false
end
end
module Number
def to_currency(options = {})
number = self
default = Currency::DEFAULT.stringify_keys
options = default.merge(options.stringify_keys)
precision = options["precision"] || default["precision"]
unit = options["unit"] || default["unit"]
position = options["position"] || default["position"]
separator = precision > 0 ? options["separator"] || default["separator"] : ""
delimiter = options["delimiter"] || default["delimiter"]
begin
parts = number.with_precision(precision).split('.')
number = parts[0].to_i.with_delimiter(delimiter) + separator + parts[1].to_s
position == "before" ? unit + number : number + unit
rescue
number
end
end
def with_delimiter(delimiter=",", separator=".")
number = self
begin
parts = number.to_s.split(separator)
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
parts.join separator
rescue
self
end
end
def with_precision(precision=3)
number = self
"%01.#{precision}f" % number
end
end
end
class Fixnum; include Currency::Number; end
class Bignum; include Currency::Number; end
class Float; include Currency::Number; end
class String; include Currency::String; end
Para ter estes novos métodos funcionando basta adicionar o código acima ao arquivo "environment.rb". Veja alguns exemplos de uso:
number = 9999.99
# using default settings
puts number.to_currency # $9,999.99
# using Brazilian Real
puts number.to_currency(Currency::BRL) # R$9.999,99
# using US Dollar
puts number.to_currency(Currency::USD) # US$9,999.99
# setting default to Brazilian Real
silence_warnings do
Currency::DEFAULT = Currency::BRL
end
# using default settings, now
# Brazilian Real
number.to_currency # R$9.999,99
puts '199.99'.to_number # 199.99
puts '199,99'.to_number # 199.99
puts '+199,99'.to_number # 199.99
puts '-199,99'.to_number # -199.99 - Permalink
- Trackback
- Comentários (10)
- Ao som de: No Fun At All – Ultramar
Textos escritos por
Comentários #
Achei interessante este método para uso no modelo e no controller, mas já trabalhei bastante com valores no BielBid (http://bielbid.com.br) e não senti necessidade.
Temos que ter atenção para não confundir as coisas, como se trata de uma formatação de valores, este método deve ser utilizado basicamente no view mesmo.
O mais correto é trabalhar com o valor cru (raw data) no modelo.
Não é qualquer um que vai pegar a sua extensão e vai utilizá-la respeitando os conceitos de MVC!
Abraços
Concordo 100% com o Rafael (como já tinha me expressado no fórum em http://forum.rubyonbr.org/forums/1/topics/1680#posts-9535).
No Spesa, deixo o usuário escolher se ele quer enviar os dados como '100.00' ou '100,00'. Fiz isso usando um attr_accessor de nome formatted_amount. No before_validation, uso o método to_number. E tem o caso contrário que é converter o atributo formatted_amount com amount.to_currency no after_find.
Como vocês fariam essa lógica? A de exibição, acho mais simples, pois já existe um método nativo. Mas e a de conversão de uma string '100,00' para número?
Sou adepto de modelos gordos[1]. Então, *para mim*, faz todo o sentido.
[1] http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model
perfeito cara, eu custumo fazer isso com algumas gambiarras, hehehhehee, sempre tive medo de tentar um override da classe, por nao ter tempo de estudar corretamnete como elas funcionam.. mas pelo visto, voce ja esta craque nisto.
parabens.
Muito bom Nando. veio numa hora quase certa
Opa, Seu post salvou uma vida heheh! :-)
Muito bom...
Abraços
Olá Nando, estou utilizando esse modulo e está sendo muito útil.
Pra mim eu uso nos controllers quando vou gerar relatórios.
Gostaria de saber se você tem ou conhece algum script para converter um valor real para extenso.
Obrigado.
Se não estou enganado, o Brazilian Rails tem uma gem para isso. http://github.com/tapajos/brazilian-rails/tree/master
Ola nando muito bom esta solucao
mas eu estou com dificuldade e implenar isso aqui no meu projeto :/
dentro do arquivo "environment.rb" eu coloco ele dentro Rails::Initializer.run do |config|
ou aonde? desculpe minha ignorância mas ptus isso iria me ajudar muito
obrigado.
so para complementar quanto eu tento usar ele
ele me da esse erro
undefined method `to_currency' for #
Deixe um comentário