Why do form_helpers look directly into the database?

2 views
Skip to first unread message

harm

unread,
May 22, 2007, 5:00:48 PM5/22/07
to Ruby on Rails: Core, harmd...@gmail.com
Hi all,

I have a small testing RailsApp with a simple model, which has a float
attribute called price:

In the model I have overridden the price() method:

class Product < ActiveRecord::Base
def price
return "bla"
end
end

In the console, it behaves as expected:
p = Product.new
p.price = 12.12
p.price
>> "bla"

However, Using the form helper methods, it appears they are not using
the instance methods:

for instance:

<%= form.text_field :price %>

displays: 12.12 in my view, and ignores the overridden AR instance
method.

Why do the form_helpers work this way?
Is this a bug? Or is this approach chosen on purpose?

Regards,

Harm de Laat
Kabisa ICT

Mislav Marohnić

unread,
May 22, 2007, 5:47:39 PM5/22/07
to rubyonra...@googlegroups.com
On 5/22/07, harm <harmd...@gmail.com> wrote:

However, Using the form helper methods, it appears they are not using
the instance methods:

This issue already has a thread: "Ticket #2322".
Here is the actual ticket: http://dev.rubyonrails.org/ticket/2322

Kevin Clark

unread,
May 22, 2007, 5:56:17 PM5/22/07
to rubyonra...@googlegroups.com
There are actually several tickets that show this behavior (bug?). I
believe the OP is writing to ask whether this is the desired behavior,
or whether it should be treated as a bug and we should be pushing to
commit patches relating to it.

Kev


--
Kevin Clark
http://glu.ttono.us

Harm de Laat

unread,
May 22, 2007, 6:03:15 PM5/22/07
to rubyonra...@googlegroups.com
It seems the ticket is closed?
Any reason why? Should we reopen it?


On 5/22/07, Mislav Marohnić <mislav....@gmail.com > wrote:

Kevin Clark

unread,
May 22, 2007, 6:05:11 PM5/22/07
to rubyonra...@googlegroups.com
Feel free to reopen it, but as this discussion covers multiple tickets
(and intended behavior), it should take place here.

Harm de Laat

unread,
May 22, 2007, 6:11:09 PM5/22/07
to rubyonra...@googlegroups.com
At least to me, it 'feel's' like kinda odd behavior.
It seems inconsistent:

IMHO product.price() should display the exact same value as form.text_field :price.
Also the method header is: text_field (object_name, method, options = {}), which imho implies that 'method' is going to be called on 'object_name'.

Cheers, harm!

Mislav Marohnić

unread,
May 22, 2007, 6:57:55 PM5/22/07
to rubyonra...@googlegroups.com
On 5/23/07, Harm de Laat <harmd...@gmail.com> wrote:
At least to me, it 'feel's' like kinda odd behavior.
It seems inconsistent:

There must have been some reason for this behavior.

Michael Koziarski

unread,
May 22, 2007, 7:21:52 PM5/22/07
to rubyonra...@googlegroups.com
> There must have been some reason for this behavior.

validates_numericality_of

if you have an integer field, and the user types in "a12345" instead
of "12345". When displaying error messages you want to display the
value before it was typecast, otherwise it'd just be set to 0. So the
field helper doesn't look directly in the database, it uses
price_before_type_cast, if it exists.

So the behaviour is intentional, if somewhat opaque. Perhaps what's
needed is a way to make it easier to wrap attributes with custom
accessors and mutators?
--
Cheers

Koz

Nik Wakelin

unread,
May 22, 2007, 7:36:50 PM5/22/07
to rubyonra...@googlegroups.com
Ah lame I totally just patched this.

Maybe we could fix validates_numericality_of? Rather than changing
every field helper because of one case? I suppose it is more difficult
that way around however.

The docs really do make it seem like it calls the method. So we'd need
to remember to change those :)


--
Nik Wakelin
(027) 424 5433
munky...@gmail.com

Michael Koziarski

unread,
May 22, 2007, 10:11:02 PM5/22/07
to rubyonra...@googlegroups.com
On 5/23/07, Nik Wakelin <munky...@gmail.com> wrote:
>
> Ah lame I totally just patched this.
>
> Maybe we could fix validates_numericality_of? Rather than changing
> every field helper because of one case? I suppose it is more difficult
> that way around however.

It's also totally random behaviour to sometimes get a String from an
otherwise numeric attribute. I'm not sure that there's a really
simple fix that'll magically solve every case we could come across,
but I do believe that if we find the cases where this behaviour is
biting people, we'll probably be able to solve those cases nicely.

My understanding is that the most common case is something along the
lines of "I want to store the number of cents instead of a dollar
amount"? What else breaks?

It seems the real problem is two fold:

1) it's kinda surprising that overriding the accessors doesn't
automatically work
2) The docs outright lie and tell you that it will work.

> The docs really do make it seem like it calls the method. So we'd need
> to remember to change those :)

Indeed.


--
Cheers

Koz

Nik Wakelin

unread,
May 22, 2007, 11:21:58 PM5/22/07
to rubyonra...@googlegroups.com
What about:


1) If an overridden accessor is there, (i.e you've defined
Product#price) then that gets called
2) Otherwise, we call price_before_type_cast

(i.e the opposite of the current logic :))

And we amend the documents.

On 5/22/07, Michael Koziarski <mic...@koziarski.com> wrote:
>

Mislav Marohnić

unread,
May 23, 2007, 12:44:02 AM5/23/07
to rubyonra...@googlegroups.com
On 5/23/07, Nik Wakelin <munky...@gmail.com> wrote:

  1) If an overridden accessor is there, (i.e you've defined
Product#price) then that gets called
   2) Otherwise, we call price_before_type_cast

That's still no good. You want to be able to display to the user exactly what he entered, unconditionally. Doing what you suggested would make the behavior even more inconsistent.

Nik Wakelin

unread,
May 25, 2007, 1:22:40 AM5/25/07
to rubyonra...@googlegroups.com
How about this for a solution.

The real problem seems to be that people want to format attributes
before they display them (credit card, phone number). So, how about we
allow that. Could be as simple as:

<%= text_field :person, :name, :formatter => :random -%>

class Person < ActiveRecord::Base

def random(value)
value.upcase * 4
end

end

Thoughts?

Josh Susser

unread,
May 25, 2007, 2:05:50 AM5/25/07
to rubyonra...@googlegroups.com
That takes care of the transformation in one direction, but not the
other. I suppose you can just handle that the usual way with a
before_validation callback. Sorry if that's silly, I haven't been
following this thread in detail.

--josh

--
Josh Susser
http://blog.hasmanythrough.com


Nik Wakelin

unread,
May 25, 2007, 2:10:04 AM5/25/07
to rubyonra...@googlegroups.com
I think the only way you want to format it is for display to the end
user, store it in the database in a different format.

Harm de Laat

unread,
May 25, 2007, 2:38:27 AM5/25/07
to rubyonra...@googlegroups.com
In the example I was needing this for: We need to allow people to enter prices in dutch format, i.e.:
12,25 (notice the comma). Before storing this into the database we would like to transform this value to: 12.25 (notice the dot).
When displaying the value in the view we need to do the opposite, retrieve the value from the database and replace dots by comma's and display the value to the end user.

We solved this easily using a virtual attribute, however, it would be nice if it were just possible to override getters and setters in AR. It just seems awkward that this is not possible for helper methods.

Why is this so hard? Why not save the original value typed in by the end user, and if validation goes wrong just display the original entered value, else just use the overridden setter?

I might be missing something though....

Steven A Bristol

unread,
May 25, 2007, 8:04:13 AM5/25/07
to rubyonra...@googlegroups.com
> On May 24, 2007, at 10:22 PM, Nik Wakelin wrote:
>
> > How about this for a solution.
> >
> > The real problem seems to be that people want to format attributes
> > before they display them (credit card, phone number). So,
how about we
> > allow that. Could be as simple as:
> >
> > <%= text_field :person, :name, :formatter => :random -%>
> >


+1

I would love for this to be in core. I have been feeling the pain of
hacking around this for sometime.

Nik, will you do the patch or should I?

Koz, do you think this would be applied?


--
Thank you,
Steven A Bristol
st...@lesseverything.com

Nik Wakelin

unread,
May 25, 2007, 6:52:31 PM5/25/07
to rubyonra...@googlegroups.com
I'm happy to put together a patch if everyone is happy with that soution...?

madevi...@gmail.com

unread,
May 25, 2007, 7:57:24 PM5/25/07
to Ruby on Rails: Core
On 5/25/07, Nik Wakelin <munky...@gmail.com> wrote:
> The real problem seems to be that people want to format attributes
> before they display them (credit card, phone number). So, how about we
> allow that. Could be as simple as:

Sometimes (or perhaps generally) form builders and objects are too
closely tied -- surely you do not want to pollute your model with a
lot of user interface stuff. Instead, a level of indirection is
useful, such as a form model:

class ProductForm
def initialize(object)
@object = object
end

def dutch_price
('%.2f' % @object.price).gsub('.', ',')
end

def dutch_price=(price)
@object.price = price.to_s.gsub(',', '.')
end

def method_missing(name, *args, &block)
@object.send(name, *args, &block)
end
end

Now you can do:

<% form_for :product, @product do |form| %>
<%= form.text_field :title %>
<%= form.text_field :dutch_price %>
<% end %>

where @product could be initialized thus:

@product = ProductForm.new(Product.find(params[:id]))

Alexander.

Michael Koziarski

unread,
May 25, 2007, 9:34:39 PM5/25/07
to rubyonra...@googlegroups.com
> I'm happy to put together a patch if everyone is happy with that soution...?

Another thing to check is if it's feasible to make the form helpers
only use _before_type_cast if the field is invalid? Perhaps that'll
allow for a relatively low-impact solution?


--
Cheers

Koz

Max Muermann

unread,
May 27, 2007, 6:54:50 PM5/27/07
to rubyonra...@googlegroups.com

This would mean that if there is a validation error in some other
field, the typecast value gets displayed back to the user. We are
using Chronic for date parsing - I don't want the shiny natural
language date that the user entered to disappear halfway through the
validation process.

Maybe only use before_type_cast if there are _any_ validation errors
for the current submission?

I don't think there's anything wrong with the current approach, but I
agree that the documentation could be clearer.

--max

>
> --
> Cheers
>
> Koz
>
> >
>

Derrick Spell

unread,
May 31, 2007, 1:46:57 AM5/31/07
to rubyonra...@googlegroups.com

Here's another +1 on being able to format the value in a form helper
before it's displayed. This shouldn't be in my model since it's
purely a display issue. I'd be happy if I could specify another
helper method to perform the formatting. Something like:

<%= text_field :product, :price, :formatter => :number_to_currency -%>


-Derrick Spell

eventualbuddha

unread,
May 31, 2007, 11:48:12 AM5/31/07
to Ruby on Rails: Core
Agreed. This would be a useful addition. While we're on the topic,
what solution for setters does this naturally work with? We can't just
discard the original value that came from the user in case we need to
display it again.

-bd

On May 30, 10:46 pm, "Derrick Spell" <derrick.sp...@gmail.com> wrote:


> On 5/25/07, Steven A Bristol <stevenbris...@gmail.com> wrote:
>
>
>
>
>
> > > On May 24, 2007, at 10:22 PM, Nik Wakelin wrote:
>
> > > > How about this for a solution.
>
> > > > The real problem seems to be that people want to format attributes
> > > > before they display them (credit card, phone number). So,
> > how about we
> > > > allow that. Could be as simple as:
>
> > > > <%= text_field :person, :name, :formatter => :random -%>
>
> > +1
>
> > I would love for this to be in core. I have been feeling the pain of
> > hacking around this for sometime.
>
> > Nik, will you do the patch or should I?
>
> > Koz, do you think this would be applied?
>
> > --
> > Thank you,
> > Steven A Bristol

> > s...@lesseverything.com

Reply all
Reply to author
Forward
0 new messages