Десятичные числа и запятые при вводе числа в форму Ruby on Rails
Какой лучший способ Ruby/Rails позволяет пользователям использовать десятичные знаки или запятые при вводе числа в форму? Другими словами, я хотел бы, чтобы пользователь мог ввести 2000.99 и не получить 2.00 в моей базе данных.
Есть ли наилучшая практика для этого?
- Обновить ---
Работает ли gsub с поплавками или bigintegers? Или рельсы автоматически вырезают номер при входе в форму float или ints? Я попытался использовать self.price.gsub( ",", "), но получим метод undefined `gsub 'для 8: Fixnum", где 8 - это номер, который я ввел в форму.
Ответы
Ответ 1
У меня была аналогичная проблема, пытаясь использовать локализованный контент внутри форм. Вывод локализации относительно прост с использованием встроенных методов ActionView::Helpers::NumberHelper
, но анализ локализованного ввода не поддерживается ActiveRecord
.
Это мое решение, пожалуйста, скажите мне, что я делаю что-то неправильно. Мне кажется слишком простым, чтобы быть правильным решением. Благодарю!:)
Прежде всего, добавьте метод String
.
class String
def to_delocalized_decimal
delimiter = I18n::t('number.format.delimiter')
separator = I18n::t('number.format.separator')
self.gsub(/[#{delimiter}#{separator}]/, delimiter => '', separator => '.')
end
end
Затем добавьте метод класса в ActiveRecord::Base
class ActiveRecord::Base
def self.attr_localized(*fields)
fields.each do |field|
define_method("#{field}=") do |value|
self[field] = value.is_a?(String) ? value.to_delocalized_decimal : value
end
end
end
end
Наконец, пусть объявить, какие поля должны иметь локализованный вход.
class Article < ActiveRecord::Base
attr_localized :price
end
Теперь в вашей форме вы можете ввести "1.936,27", а ActiveRecord
не будет вызывать ошибки при недопустимом числе, потому что он станет 1936.27.
Ответ 2
Вот несколько кодов, которые я скопировал у Грега Брауна (автора Ruby Best Practices) несколько лет назад. В вашей модели вы определяете, какие предметы "очеловечены".
class LineItem < ActiveRecord::Base
humanized_integer_accessor :quantity
humanized_money_accessor :price
end
В ваших шаблонах просмотров вам нужно ссылаться на гуманизированные поля:
= form_for @line_item do |f|
Price:
= f.text_field :price_humanized
Это определяется следующим образом:
class ActiveRecord::Base
def self.humanized_integer_accessor(*fields)
fields.each do |f|
define_method("#{f}_humanized") do
val = read_attribute(f)
val ? val.to_i.with_commas : nil
end
define_method("#{f}_humanized=") do |e|
write_attribute(f,e.to_s.delete(","))
end
end
end
def self.humanized_float_accessor(*fields)
fields.each do |f|
define_method("#{f}_humanized") do
val = read_attribute(f)
val ? val.to_f.with_commas : nil
end
define_method("#{f}_humanized=") do |e|
write_attribute(f,e.to_s.delete(","))
end
end
end
def self.humanized_money_accessor(*fields)
fields.each do |f|
define_method("#{f}_humanized") do
val = read_attribute(f)
val ? ("$" + val.to_f.with_commas) : nil
end
define_method("#{f}_humanized=") do |e|
write_attribute(f,e.to_s.delete(",$"))
end
end
end
end
Ответ 3
Вы можете попытаться удалить запятые before_validation или before_save
К сожалению, вы хотите сделать это в текстовом поле до его преобразования. Вы можете использовать виртуальный атрибут:
def price=(price)
price = price.gsub(",", "")
self[:price] = price # or perhaps price.to_f
end
Ответ 4
Мне не удалось реализовать более раннее предложение def price=(price)
виртуального атрибута, потому что метод, похоже, называет себя рекурсивно.
Я закончил удаление запятой из хэша атрибутов, так как вы подозреваете, что ActiveRecord, кажется, усекает ввод с запятыми, которые попадают в поля DECIMAL.
В моей модели:
before_validation :remove_comma
def remove_comma
@attributes["current_balance"].gsub!(',', '') # current_balance here corresponds to the text field input in the form view
logger.debug "WAS COMMA REMOVED? ==> #{self.current_balance}"
end
Ответ 5
Здесь что-то простое, что позволяет правильно считывать ввод номера. Выход будет по-прежнему с точкой вместо запятой. Это не красиво, но по крайней мере не критично в некоторых случаях.
Для этого требуется один вызов метода в контроллере, где вы хотите включить разделитель запятой. Может быть, не идеальный с точки зрения MVC, но довольно простой, например:
class ProductsController < ApplicationController
def create
# correct the comma separation:
allow_comma(params[:product][:gross_price])
@product = Product.new(params[:product])
if @product.save
redirect_to @product, :notice => 'Product was successfully created.'
else
render :action => "new"
end
end
end
Идея состоит в том, чтобы изменить строку параметров, например:
class ApplicationController < ActionController::Base
def allow_comma(number_string)
number_string.sub!(".", "").sub!(",", ".")
end
end
Ответ 6
Взгляните на i18n_alchemy для анализа и локализации даты и числа.
I18nAlchemy направлена на обработку синтаксиса даты, времени и числа на основе текущего формата I18n. Основная идея состоит в том, чтобы ORM, например ActiveRecord, автоматически принимать даты/числа, указанные в текущем формате локали, и также возвращать эти значения.