Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Customize Field Errors with Rails 5 and Bootstrap
# Adapted from https://rubyplus.com/articles/3401-Customize-Field-Error-in-Rails-5
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
html = ''
form_fields = [
'textarea',
'input',
'select'
]
elements = Nokogiri::HTML::DocumentFragment.parse(html_tag).css "label, " + form_fields.join(', ')
elements.each do |e|
if e.node_name.eql? 'label'
html = %(#{e}).html_safe
elsif form_fields.include? e.node_name
e['class'] += ' is-invalid'
if instance.error_message.kind_of?(Array)
html = %(#{e}<div class="invalid-feedback">#{instance.error_message.uniq.join(', ')}</div>).html_safe
else
html = %(#{e}<div class="invalid-feedback">#{instance.error_message}</div>).html_safe
end
end
end
html
end
@ro31337

This comment has been minimized.

Copy link

commented Sep 10, 2017

You better h(instance.error_message) and h(instance.error_message.uniq.join(', ')). If attacker has control over your error messages, you're screwed! Would be also nice to see example html/erb. It didn't work with my markup, error on line 17. Seems like I don't have class for my tag.

@plog

This comment has been minimized.

Copy link

commented Nov 9, 2017

undefined method `+' for nil:NilClass
with e['class'] += ' is-invalid'

@martinvelez

This comment has been minimized.

Copy link

commented Nov 14, 2017

I achieved this using Javascript.

<script>                                                                            
$(document).ready(function(){                                                       
  $('.field_with_errors input:first').addClass('is-invalid')                        
  $('.field_with_errors select:first').addClass('is-invalid')                       
  $('.field_with_errors textarea:first').addClass('is-invalid')                     
});                                                                                 
</script> 
@andreimoment

This comment has been minimized.

Copy link

commented Jan 11, 2018

Here's a version with the nil issue fixed: https://gist.github.com/andreimoment/515715d9d56ffbdadc25697d9db52c62

@ro31337, html_escape and its h alias seem to be unavailable for initializers. Users having control over error messages is not a common use case so I'm leaving this alone.

@pastullo

This comment has been minimized.

Copy link

commented Jun 7, 2018

How about this simpler solution which is compatible with Bootstrap 4:

# add in config/initializers/stock_errors.rb
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  html_tag.html_safe
end
@ycherniavskyi

This comment has been minimized.

Copy link

commented Jun 12, 2018

@pastullo how exactly your solution is compatible with Bootstrap 4? You just do not wrap html_tag by div with class field_with_errors, but also you do not add any necessary Bootstrap 4 from classes to highlight errors.

@rendon

This comment has been minimized.

Copy link

commented Dec 17, 2018

My approach: add your error class to the element's classes instead of wrapping it in a div.

ActionView::Base.field_error_proc = proc do |html_tag, instance_tag|
  match = html_tag.to_s.match(/class\s*=\s*"([^"]*)"/)
  return html_tag unless match[1]

  html_tag
    .to_s
    .gsub(match[0], "class=\"#{match[1]} field_with_errors\"")
    .html_safe
end

I'm not sure how good/secure it is. It's just the first solution that I came up with.

I think you will have to update the regex to handle classes with single quotes like class='my-class'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.