Как можно форматировать значение, указанное в поле редактирования Rails?
Я хотел бы сделать поля формы редактирования максимально удобными. Например, для числовых значений я хотел бы, чтобы поле отображалось запятыми (например, number_with_precision
).
Это достаточно просто на стороне дисплея, но как насчет редактирования? Есть ли хороший способ сделать это?
Я использую Rails FormBuilder. После исследования я обнаружил, что он использует InstanceTag, который получает значения для полей, используя <attribute>_value_before_type_cast
, что означает, что переопределение <attribute>
не будет вызвано.
Ответы
Ответ 1
Самое лучшее, что я придумал, - это что-то вроде этого:
<%= f.text_field :my_attribute, :value => number_with_precision(f.object.my_attribute) %>
Или my_attribute
может вернуть форматированное значение, например:
def my_attribute
ApplicationController.helpers.number_with_precision(read_attribute(:my_attribute))
end
Но вы все равно должны использовать :value
<%= f.text_field :my_attribute, :value => f.object.my_attribute %>
Это похоже на большую работу.
Ответ 2
Я предпочитаю ваш первый ответ, причем форматирование выполняется в представлении. Однако, если вы хотите выполнить форматирование в модели, вы можете использовать методы-обёртки для getter и setter и не использовать полностью значение параметра: value.
У вас получится что-то вроде этого.
def my_attribute_string
foo_formatter(myattribute)
end
def my_attribute_string=(s)
# Parse "s" or do whatever you need to with it, then set your real attribute.
end
<%= f.text_field :my_attribute_string %>
Railscasts покрыл это с помощью объекта Time в текстовом поле в эпизоде # 32. Действительно умная часть этого - то, как они обрабатывают ошибки проверки. Стоит посмотреть эпизод только для этого.
Ответ 3
Это старый вопрос, но в случае, если кто-то сталкивается с этим, вы можете использовать помощники number_to_X. У них есть все атрибуты, которые вы когда-либо хотели бы отображать свое значение редактирования:
<%= f.text_field :my_number, :value => number_to_human(f.object.my_number, :separator => '', :unit => '', :delimiter => '', :precision => 0) %>
Также доступно больше атрибутов: http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html
Ответ 4
Если вы хотите, чтобы формат был создан или поддерживался во время редактирования, вам нужно будет добавить Javascript для реализации "масок". Вот демо.
Это был первый хит эти результаты.
Ответ 5
Вы можете использовать плагин number_format. Указав number_format
для существующего числового атрибута внутри вашей модели, атрибут теперь будет отображаться как форматированный для Rails во всех формах и представлениях. Он также будет анализироваться обратно из этого формата (при назначении через формы) перед вставкой в базу данных. (Плагин также создает чисто числовые unformatted_<attribute-name>
аксессоры, которые могут использоваться для арифметики или для прямого численного назначения или поиска для бесшовной интеграции.)
class MyModel < ActiveRecord::Base
# this model has the balance attribute, which we
# want to display using formatting in views,
# although it is stored as a numeric in the database
number_format :balance,
:precision => 2,
:delimiter => ',',
:strip_trailing_zeros => false
def increment_balance
unformatted_balance += 10
end
Вы также можете объединить вышеуказанное с решением Javascript, которое может заставить пользователя поддерживать десятичную точку и тысячи разделителей на месте во время редактирования, хотя это действительно не нужно.
Ответ 6
Я сделал что-то подобное. Мы форматируем время и длину, используя собственный конструктор форм. Он использует существующее текстовое поле, но обертывает его так, чтобы значение можно было настроить:
class SuperFormBuilder < ActionView::Helpers::FormBuilder
include ApplicationHelper
include FormHelper
include ActionView::Helpers::TagHelper
include ActionView::Helpers::FormTagHelper
def length_field(label,*args)
scale = 'medium'
args.each do |v|
if v.has_key?(:scale)
scale = v[:scale]
v.delete(:scale)
end
end
value = length_conversion(@object.send(label.to_sym),scale)
options = (args.length > 0) ? args.pop : {}
return has_error(label, text_field_tag(field_name(label),value,*args) + ' ' + length_unit(scale))
end
private
def field_name(label)
return @object_name + "[#{label}]"
end
def has_error(label, output)
return "<div class='fieldWithErrors'>#{output}</div>" if @object.errors[label]
return output
end
И он используется следующим образом:
<%= form_for( @section, {:action => 'save', :id => @section.id}, :builder => SuperFormBuilder) do |sf| %>
<%= sf.length_field :feed_size_min_w, :size => 3, :scale => 'small' %>
<% end %>
Конечным результатом является значение в соответствующем модуле, основанное на их выборе на системе (метрическая, имперская) и шкале IE small = дюймы или миллиметры.
Я в основном скопировал метод text_field из существующего конструктора форм, который сам использует text_field_tag.
Есть два gotchas: 1) Зная имя поля объекта и как получить доступ к объекту, чтобы получить значение, которое вы хотите отформатировать. 2) Как правильно получить имя при отправке формы, оно является частью хэша правильных параметров.
Конструктору формы присваивается переменная класса @object. Вы можете получить значение поля, используя метод .send. В моем случае я отправляю ярлык: feed_size_min_w в @object и возвращаю его длину. Затем я преобразую его в желаемый формат и передаю его в text_field_tag.
Имя поля является ключом к тому, что оно заканчивается в хеше params, в моем примере - params [: sections] one. Я сделал небольшую вспомогательную функцию с именем field_name, которая позаботится об этом.
Наконец, has_error обертывает поле в div с ошибкой, если на этой метке есть ошибки.