Validation and FieldWithErrors field selection tags
Is it normal behavior to not get select <div class="fieldWithErrors"> tags that have validation errors? I personally do not see the reasons why select tags should be processed differently than tags of other forms (input, textarea).
I get an error in the error_messages_for and error_message_on for this field.
PS. I changed the value of ActionView::Base.field_error_proc to get span tags instead of div, but this is not a problem.
ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| #if I puts html_tag here I only get the <input> tags "<span class=\"fieldWithErrors\">#{html_tag}</span>" } Since I could not find out why select tags were not included in this Proc, I created a helper method that does preety very much the same.
def field_with_error(object, method, &block) if block_given? if error_message_on(object, method).empty? concat capture(&block) else concat '<span class="fieldWithErrors">' + capture(&block) + '</span>' end end end I use it in my views like this:
<% field_with_error @some_object, :assoc do %> <%= f.select(:assoc_id, @associations.collect {|assoc| [ asoc.name, assoc.id ] }) %> <% end %> If someone knows a better or cleaner way to do this, I am open to suggestions.
The problem (at least for me) was that my f.select :whatever_id looking at the object.errors object for the key :whatever_id , when my check was actually on :whatever , not :whatever_id .
I circumvented this nasty problem by changing
object.errors.on(@method_name) to
object.errors.on(@method_name) || object.errors.on(@method_name.gsub(/_id$/, '')) Here's the diff (versus Rails 2.3.4):
diff --git a/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb b/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb index 541899e..5d5b27e 100644 --- a/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb +++ b/vendor/rails/actionpack/lib/action_view/helpers/active_record_helper.rb @@ -247,7 +247,7 @@ module ActionView alias_method :tag_without_error_wrapping, :tag def tag(name, options) if object.respond_to?(:errors) && object.errors.respond_to?(:on) - error_wrapping(tag_without_error_wrapping(name, options), object.errors.on(@method_name)) + error_wrapping(tag_without_error_wrapping(name, options), object.errors.on(@method_name) || object.errors.on(@method_name.gsub(/_id$/, ''))) else tag_without_error_wrapping(name, options) end @@ -256,7 +256,7 @@ module ActionView alias_method :content_tag_without_error_wrapping, :content_tag def content_tag(name, value, options) if object.respond_to?(:errors) && object.errors.respond_to?(:on) - error_wrapping(content_tag_without_error_wrapping(name, value, options), object.errors.on(@method_name)) + error_wrapping(content_tag_without_error_wrapping(name, value, options), object.errors.on(@method_name) || object.errors.on(@method_name.gsub(/_id$/, ''))) else content_tag_without_error_wrapping(name, value, options) end I found this blog post which seems to relate to this:
Hope this is helpful!
Here is how I solve this problem.
I create a specific select field_with_errors wrapper:
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| if html_tag =~ /^<input/ %{<div class="field_with_errors">#{html_tag}<label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>}.html_safe elsif html_tag =~ /^<select/ %{<div class="field_with_errors" id="select-error">#{html_tag}</div>}.html_safe else %{<div class="field_with_errors">#{html_tag}</div>}.html_safe end end CSS:
#select-error { border: 1px solid red; overflow-y: auto; overflow-x: hidden; } And I change my checks to: what_id instead of: any
validates :whatever_id, :presence => true I forgot, select:
f.collection_select(:whatever_id, Whatever.all, :id, :name, prompt: t(:please_choose)) Another way can be inserted at the method or controller level or in environment.rb:
ActionView :: Base.field_error_proc = proc {| input, instance | input}