TIP: Using field_error_proc to add style attributes to form


#1

I just put this up on the wiki, and thought I’d share in case it’s
useful to anyone else. This is handy if you donâ??t want to wrap your
input elements inside a div when an error occurs, but instead want to
add some sort of CSS style to fields with errors:

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
msg = instance.error_message
error_style = “background-color: #f2afaf
if html_tag =~ /<(input|textarea|select)[^>]+style=/
style_attribute = html_tag =~ /style=[’"]/
html_tag.insert(style_attribute + 7, "#{error_style}; ")
elsif html_tag =~ /<(input|textarea|select)/
first_whitespace = html_tag =~ /\s/
html_tag[first_whitespace] = " style=’#{error_style}’ "
end
html_tag
end

(wrapping fields in a div always seems to mess my layout up a bit)

From: http://wiki.rubyonrails.com/rails/pages/
HowtoChangeValidationErrorDisplay

Duane J.
(canadaduane)
http://blog.inquirylabs.com/


#2

On 1/19/06, Duane J. removed_email_address@domain.invalid wrote:

html_tag.insert(style_attribute + 7, "#{error_style}; ")

http://wiki.rubyonrails.com/rails/pages/HowtoChangeValidationErrorDisplay

Looks interesting. My first Rails program involves a “multiple child
record update” scenario, rendering a collection of partials and using
the :index attribute of the resulting params array. (I hope my
OO/Rails lingo is close…) Anyway, is there any way to get this kind
of error identification by the offending input widget working in that
scenario? It’s been automatic when updating a single record.

Thanks!

  • Ian

#3

On Jan 19, 2006, at 6:00 PM, Ian H. wrote:

msg = instance.error_message

the :index attribute of the resulting params array. (I hope my
OO/Rails lingo is close…) Anyway, is there any way to get this kind
of error identification by the offending input widget working in that
scenario? It’s been automatic when updating a single record.

Thanks!

There’s a super-secret and mostly undocumented way of doing this
that’s kind of handy, actually. It looks like this:

<% for @comment in @post.comments %>
<%= text_field ‘comment[]’, ‘author’ %>
<%= text_field ‘comment[]’, ‘body’ %>
<% end %>

The FormTagHelper will pick up the square brackets and realize you
want the index of the object in there, producing HTML like this:


It’s important that you assign a class variable in the loop (i.e.
@comment” not “comment” in the for loop above). If that’s all set
up correctly, then you should be able to get the same automagic error
identification results as you do for normal (single) fields.

Duane J.
(canadaduane)
http://blog.inquirylabs.com/


#4

On Jan 19, 2006, at 6:00 PM, Ian H. wrote:

msg = instance.error_message

the :index attribute of the resulting params array. (I hope my
OO/Rails lingo is close…) Anyway, is there any way to get this kind
of error identification by the offending input widget working in that
scenario? It’s been automatic when updating a single record.

Thanks!

  • Ian

Oh, it just occurred to me what you’re asking. :slight_smile:

You’ll need to call the “valid?” method on each object in the array
so that the validation code can be run, and thus, any errors that
should show up will.

For example, in your controller:

all_valid = @post.comments.all? { |c| c.valid? }

The above line has the effect of both adding error messages to each
objects internal error array, and returning ‘true’ or ‘false’
depending on whether or not all comments are valid.

Duane J.
(canadaduane)
http://blog.inquirylabs.com/


#5

Hi !

2006/1/20, Duane J. removed_email_address@domain.invalid:

all_valid = @post.comments.all? { |c| c.valid? }

Sorry Duane, but that won’t work if one instance is invalid.
Enumerable#all? short-circuits evaluation when it can, so c.valid?
might not run on the last entries in the array.

A better way, I think, would be:

all_valid = @post.comments.inject(true) {|memo, c| c.valid? && memo }

c.valid? will be evaluated for all instances, and all_valid will be
true/false, as in the initial example.

I hope I’m not making a mistake in full view of the public :slight_smile:

Bye !


#6

Hmm. Ok, I have been doing

<%= text_field ‘comment’,‘author’, :index => comment_counter %>

or something like that, but that uses a local variable as handed over
in the render call. I need to look and see but I guess I was not
instantiating a class variable.

The other sticky wicket is the ajax autocomplete stuff. It works
wonderfully with the basic single record update/insert where there is
no index. I assume I will have to open the hood on the ajax stuff to
make it work in the context of a form with an arbitrary number of
indexed records on it.

Thank you so much for taking the time to respond!

  • Ian

On 1/20/06, Duane J. removed_email_address@domain.invalid wrote:

style to fields with errors:
end

that’s kind of handy, actually. It looks like this:
value=“Duane”>
Duane J.
(canadaduane)
http://blog.inquirylabs.com/


"Her faults were those of her race and sex; her virtues were her own.
Farewell, and if for ever - "

– “Travels with a Donkey in the Cevennes” by Robert Louis Stevenson