Forum: Ruby on Rails [TIP] Making an intelligent form fields

Announcement (2017-05-07): is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see and for other Rails- und Ruby-related community platforms.
Kamil Kukura (Guest)
on 2006-03-10 00:32
(Received via mailing list)
After searching arround I found a quite smart solution to me for binding
form fields to model in an active way. I use aggregations with single
value objects such as

class Percentage
   attr_accessor :value

   def initialize(value)
     @value = (value.is_a? String) ?' %', '').to_f : value

   def to_s
     return unless value
     sprintf('%.2f %%', value)

This is an object that takes either float or string (with possible %
character in it) and viewed as string looks like "1.23 %". So I can
easily create an intelligent "shadow" attribute for interaction:

     composed_of :i_discount_rate, :class_name => 'Percentage',
                 :mapping => %w(discount_rate value)

Using i_discount_rate in form it makes value of discount_rate shown in
text field pretty with % sign. But we cannot pass it to the model
because in mass-assignment everything is just string from request.

So I used reflection on aggregation and as attributes are about to be
processed, they are "objectized", so attributes[:i_discount_rate] will
gain a real Percentage object:

    def attributes=(attributes)
      attributes.each do |param, value|
        aggregation = self.class.reflect_on_aggregation(param.to_sym)
        if aggregation
          attributes[param] =


Now an user can enter "2%", "2.0 %", "2.1  %  ", etc. and everything is
acceptable. We can now create value object for money so field "54,20
EUR" is perfectly acceptable. And there can be objects for entering date
like "+3 days" and so on.

The mechanizm for "i_attributes" can be enhanced similiary as Date is
expanded into form fields. So for example we can have aggregation

    composed_of :i_amount, :class_name => 'Amount',
                :map => [%w(a_count count), %w(a_units units)]

And then helper used like

    amount_field 'order_item', 'i_amount'

which renders to one text field and one select box such as:

    <input type="text" name="order_item[i_amount(count)]"/>
    <select name="order_item[i_amount(units)]">
      <option value="l">liters</option>
      <option value="t">tons</option>
      <option value="pc">pieces</option>

That's it.

Karel M. (Guest)
on 2006-05-04 10:37
Great! Just what I was looking for.

This topic is locked and can not be replied to.