22

The error messages for my rails form look terrible with bootstrap. Does anyone know a solution for better (nice looking) error messages? I use Rails and Bootstrap.

My form (it's a helper) is like this:

<%= form_for(@user) do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-inline">
    <%= f.text_field :email, class:'input-large', placeholder:'Test' %>
<!--   </div>
  <div class="actions"> -->
    <%= f.submit class:'btn btn-large btn-success' %>
  </div>
<% end %>

The error message

MMM
  • 307
  • 8
  • 18
Fawyd
  • 1,435
  • 3
  • 13
  • 19

8 Answers8

24

Take a look at how Michael Hartl does it in railstutorial. screenshot

And thats the used css:

#error_explanation {
  color: #f00;
  ul {
    list-style: none;
    margin: 0 0 18px 0;
  }
}

.field_with_errors {
  @extend .control-group;
  @extend .error;
 }

He describes everything here.

If you also want the little star at the beginning of every line you have to include it in your form:

     <div id="error_explanation">
        <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
        <ul>
          <% @user.errors.full_messages.each do |msg| %>
            <li> * <%= msg %></li>    <--- insert here
          <% end %>
        </ul>
     </div>
      ...
Chloe
  • 25,162
  • 40
  • 190
  • 357
crispychicken
  • 2,592
  • 2
  • 33
  • 50
  • 3
    Definitely good to scaffold a form in the beginning and refactor the code after - so you have a clean first-time setup. KentTucky's mention to watch the process of Michael Hartl was a very good input. Thank you, @KentTucky . – Fawyd Mar 10 '13 at 15:09
  • This requires including Bootstrap source SASS code. This makes your JS and CSS compiled assets much larger. You can't use the CDN version when using this as `.error` and `.control-group` are unavailable. – Chloe Jun 06 '17 at 21:00
  • In Bootstrap 4, we should be extending the `.is-invalid` class on the input. I got this working with `.field_with_errors input { @extend .is_invalid }` – Igbanam Jan 15 '20 at 10:29
15

A little late I realize, but I just ran into this today with Rails 4 and Bootstrap 3, I ended up making a view helper to display errors using a panel:

Rails 4 / Bootstrap 3

def errors_for(object)
    if object.errors.any?
        content_tag(:div, class: "panel panel-danger") do
            concat(content_tag(:div, class: "panel-heading") do
                concat(content_tag(:h4, class: "panel-title") do
                    concat "#{pluralize(object.errors.count, "error")} prohibited this #{object.class.name.downcase} from being saved:"
                end)
            end)
            concat(content_tag(:div, class: "panel-body") do
                concat(content_tag(:ul) do
                    object.errors.full_messages.each do |msg|
                        concat content_tag(:li, msg)
                    end
                end)
            end)
        end
    end
end

enter image description here

Rails 4 / Bootstrap 4 Beta

def errors_for(object)
    if object.errors.any?
        content_tag(:div, class: "card border-danger") do
            concat(content_tag(:div, class: "card-header bg-danger text-white") do
                concat "#{pluralize(object.errors.count, "error")} prohibited this #{object.class.name.downcase} from being saved:"
            end)
            concat(content_tag(:div, class: "card-body") do
                concat(content_tag(:ul, class: 'mb-0') do
                    object.errors.full_messages.each do |msg|
                        concat content_tag(:li, msg)
                    end
                end)
            end)
        end
    end
end

enter image description here

Rails 4 / Bootstrap 4 Beta List Group Variation

def errors_for(object)
    if object.errors.any?
        content_tag(:div, class: "card border-danger") do
            concat(content_tag(:div, class: "card-header bg-danger text-white") do
                concat "#{pluralize(object.errors.count, "error")} prohibited this #{object.class.name.downcase} from being saved:"
            end)
            concat(content_tag(:ul, class: 'mb-0 list-group list-group-flush') do
                object.errors.full_messages.each do |msg|
                    concat content_tag(:li, msg, class: 'list-group-item')
                end
            end)
        end
    end
end

enter image description here

I dropped it in application_helper and call it in my form views

<%= errors_for(@user) %>

Maybe someone will stumble upon this and find it useful.

Rabbott
  • 4,282
  • 1
  • 30
  • 53
5

Just in case someone stumbles here and is using Bootstrap 4 alpha with rails 5 and bootstrap_form_for gem. I use:

<div class="form-group">
  <%= f.alert_message "Please fix the errors below." %>
</div>

which looks really nice.

enter image description here

Kick Buttowski
  • 6,709
  • 13
  • 37
  • 58
Jay Killeen
  • 2,832
  • 6
  • 39
  • 66
4

I have implemented Rabbott's view helper in Rails 5 and Bootstrap 4:

def errors_for(object)
    if object.errors.any?
      content_tag(:div, class: 'card text-white bg-danger mb-3') do
        concat(content_tag(:div, class: 'card-header') do
          concat(content_tag(:h4) do
            concat "#{pluralize(object.errors.count, 'error')} prohibited this #{object.class.name.downcase} from being saved:"
          end)
        end)
        concat(content_tag(:div, class: 'card-body') do
          concat(content_tag(:ul) do
            object.errors.full_messages.each do |msg|
              concat content_tag(:li, msg)
            end
          end)
        end)
      end
    end
  end

And it looks like this: enter image description here

Rajkaran Mishra
  • 4,532
  • 2
  • 36
  • 61
3

Bootstrap 4 Alpha 6

I copied the compiled Bootstrap CSS from

https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css

Searched for .has-danger, copied all the classes, did a search & replace on .has-danger for .field_with_errors, and I also added .field_with_errors label

.field_with_errors label,
.field_with_errors .form-control-feedback,
.field_with_errors .form-control-label,
.field_with_errors .col-form-label,
.field_with_errors .form-check-label,
.field_with_errors .custom-control {
  color: #d9534f;
}

.field_with_errors .form-control {
  border-color: #d9534f;
}

.field_with_errors .input-group-addon {
  color: #d9534f;
  border-color: #d9534f;
  background-color: #fdf7f7;
}

.field_with_errors .form-control-danger {
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d9534f' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E");
}

I wasn't able to get the input groups addons to display correctly, as it wraps the input with a <div>.

bootstrap 4 with rails errors

Docs: https://v4-alpha.getbootstrap.com/components/forms/#validation

Honestly some of these classes are not used because Rails doesn't have an obvious way to set classes on error fields.

For the error list, I just used this simple class

#error_explanation {
  color: red;
}
Community
  • 1
  • 1
Chloe
  • 25,162
  • 40
  • 190
  • 357
0

Maybe a simpler one is search for ids and classes on the form itself. Works for any combo.

By default, this are the lines included in scaffold to arrange the error messages. You can do with them whatever you want. Just have to extend them in your css.scss file:

.field_with_errors {
  padding: 2px;
  background-color: red;
  display: table;
}

#error_explanation {
  width: 450px;
  border: 2px solid red;
  padding: 7px 7px 0;
  margin-bottom: 20px;
  background-color: #f0f0f0;
}

#error_explanation h2 {
  text-align: left;
  font-weight: bold;
  padding: 5px 5px 5px 15px;
  font-size: 12px;
  margin: -7px -7px 0;
  background-color: #c00;
  color: #fff;
}

#error_explanation ul li {
  font-size: 12px;
  list-style: square;
}

In case something is not working, check the navigator in developer mode. There you should be able to find all the html and css rails is creating...

Dieglock
  • 169
  • 1
  • 16
0

Another variation with SCSS only

#error_explanation{
  background: #f23551;
  color: #fff;
  border-radius: 4px;
  margin-bottom: 20px;
  h2{
    padding: 20px;
    margin: 0;
    font-size: 20px;
  }
  ul{
    background: #fff;
    color: #e5324a;
    border: 1px solid #F23551;
    margin: 0;
    list-style: none;
    padding: 14px 0;
    li{
      padding: 4px 20px;
      &:before {
        content: '×';
        font-weight: bold;
        font-size: 20px;
        margin-right: 10px;
      }
    }
  }
}
medBouzid
  • 7,484
  • 10
  • 56
  • 86
0

I've create a custom initializer to have each field having its own errors below it

# app/config/initializers/bootstrap_form_errors_customizer.rb

ActionView::Base.field_error_proc = proc do |html_tag, instance|
  is_label_tag = html_tag =~ /^<label/
  class_attr_index = html_tag.index 'class="' 

  def format_error_message_to_html_list(error_msg)
    html_list_errors = "<ul></ul>"
    if error_msg.is_a?(Array)
      error_msg.each do |msg|
        html_list_errors.insert(-6,"<li>#{msg}</li>")
      end
    else 
      html_list_errors.insert(-6,"<li>#{msg}</li>")
    end
    html_list_errors
  end

  invalid_div =
    "<div class='invalid-feedback'>#{format_error_message_to_html_list(instance.error_message)}</div>"

  
  if class_attr_index && !is_label_tag
    html_tag.insert(class_attr_index + 7, 'is-invalid ')
    html_tag + invalid_div.html_safe
  elsif !class_attr_index && !is_label_tag
    html_tag.insert(html_tag.index('>'), ' class="is-invalid"')
    html_tag + invalid_div.html_safe
  else
    html_tag.html_safe
  end
end