views:

140

answers:

4

Is there any way to control the float format in a form field?

I want to format a float like an integer if the modulus is 0, otherwise display the float as is. I overrode the Model accessor to do this formatting.

When an edit form is loaded, I would like to have the following transformations:

stored value | accessor returns | form field shows
---------------------------------------------------
1.0          | 1                | 1
1.5          | 1.5              | 1.5

However, form_for appears to be accessing the attribute directly, thereby displaying the float as is.

Any ideas on how to get around this? Thanks.

A: 

I do believe it will work when you do something like this:

<%= f.text_field :field_attribute, :value => format_method(f.object.field_attribute) %>

format_method is whatever method you use within the model to override the formatting when accessing it that way.

Patrick Robertson
I considered doing this early on since it keeps the formatting logic in the view layer, but I thought it might be better to push the formatting into the model so I don't have to duplicate this in views...but I guess that is what partials are for.I think I'll go with this solution. Thanks!
cotopaxi
+1  A: 

You could override the attribute reader, something like this:

def myfloat
  if @myfloat == @myfloat.to_i
    @myfloat.to_i
  else
    @myfloat
  end
end

Now the returned value are correctly formatted for your form and still usable in your application.

Veger
Yeah, I already have something like that in my model. But my question was how do I get the form_for to use the overridden attribute reader? It seems to use read_attribute or something.
cotopaxi
I do not think that read_attribute is used. According to 'Overwriting default accessors' in http://ar.rubyonrails.org/classes/ActiveRecord/Base.html, the method I described should be used when specialized behaviour is required. Which seems to be the case in your situation.
Veger
I wish this would work, but the text_field helper method grabs the value directly (i.e. it does not call the accessor).
cotopaxi
A: 

Veger's solution will work if you use read_attribute to get the "raw" value:

def myfloat
  raw = read_attribute(:myfloat)
  if raw == raw.to_i
    raw.to_i
  else
    raw
  end
end

As always when comparing floats to integers, you'd want to be careful about rounding.

zetetic
A: 

You can override respond_to? in the Model to stop value_before_type_cast from being called.

def respond_to?(*args)
  if args.first.to_s == "my_float_before_type_cast"
    false
  else
    super
  end
end

And then you need also:

def my_float
  raw = read_attribute(:my_float)
  if raw == raw.to_i
    raw.to_i
  else
    raw
  end
end
milep