5

I am using Rails 4, Twitter Bootstrap 3.0, and Devise 3.0. I am trying to get identical looking flash messages for devise and the rest of my site. So far I have this:

Within "app/views/layouts/application.html.erb":

<%= render 'layouts/messages' %>

"app/views/layouts/_messages.html.erb":

<% devise_flash %>
<% flash.each do |key, value| %>
  <div class="alert alert-<%= key %>">
    <a href="#" data-dismiss="alert" class="close">×</a>
    <%= value %>
  </div>
<% end %>

I have created a "app/helpers/devise_helper.rb" in order to override the default devise error messages:

module DeviseHelper
  def devise_error_messages!
  end
end

"app/helpers/application_helper.rb":

def devise_flash
  if controller.devise_controller? && resource.errors.any?
    flash.now[:error] = flash[:error].to_a.concat resource.errors.full_messages
    flash.now[:error].uniq!
  end
end

"app/assets/stylesheets/custom.css.scss":

.alert-error {
    background-color: #f2dede;
    border-color: #eed3d7;
    color: #b94a48;
    text-align: center; }

.alert-alert {
    background-color: #f2dede;
    border-color: #eed3d7;
    color: #b94a48;
    text-align: center; }

.alert-success {
    background-color: #dff0d8;
    border-color: #d6e9c6;
    color: #468847;
    text-align: center; }

.alert-notice {
    background-color: #dff0d8;
    border-color: #d6e9c6;
    color: #468847;
    text-align: center; }

It displays normal flash messages fine but the issue is when I have a devise error. It looks like this: enter image description here

I am trying to list the errors more like this: enter image description here

I don't want the errors to be surrounded by "". It does not need to have the bullets, but I want it to be listed vertically. I think I need to edit my devise_flash method in the "app/helpers/application_helper.rb" file.

How can I do this?

Daniel
  • 2,950
  • 2
  • 25
  • 45

2 Answers2

8

I made a wiki page within the devise wiki on github for How To: Integrate I18n Flash Messages with Devise and Bootstrap

Flash Messages For the Site

First we will make a rendered view to make the code concise. Within "app/views/layouts/application.html.erb" I added <%= render 'layouts/messages' %>.

My file looks like:

<body>
  <%= render 'layouts/header' %>
  <div class="container">
    <%= render 'layouts/messages' %>
    <%= yield %>
    <%= render 'layouts/footer' %>
  </div>
</body>

Next we have to make the messages file. Make a new file in "app/views/layouts/_messages.html.erb" and add:

<% flash.each do |key, value| %>
  <div class="alert alert-<%= key %>">
    <a href="#" data-dismiss="alert" class="close">×</a>
      <ul>
        <li>
          <%= value %>
        </li>
      </ul>
  </div>
<% end %>

This will give us flash messages for the entire site.

Flash Messages For Devise

For devise you need to override the way devise handles flash messages. Create a file called devise_helper in "app/helpers/devise_helper.rb".

Inside the file you have to create a method called devise_error_messages!, which is the name of the file that tells devise how to handle flash messages.

module DeviseHelper
  def devise_error_messages!
    return '' if resource.errors.empty?

    messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
    html = <<-HTML
    <div class="alert alert-error alert-block"> <button type="button"
    class="close" data-dismiss="alert">x</button>
      #{messages}
    </div>
    HTML

    html.html_safe
  end
end

Next in your devise views you will have to define where you want the error messages to appear. You will need to enter <%= devise_error_messages! %> within the devise pages. An example is entering this within "app/views/devise/registrations/.new.html.erb" (The sign up page)

The method call should already be within the file, but you can move the code around to customize where it is shown.

CSS For Flash Messages

If you do not want to use the odd blue and yellow alerts that come default, I have set error and alert to have the same color and success and notice to have the same color. I am using red for errors and alerts, and green for success and notice.

Within my "app/assets/stylesheets/custom.css.scss" I have:

/*flash*/
.alert-error {
    background-color: #f2dede;
    border-color: #eed3d7;
    color: #b94a48;
    text-align: left;
 }

.alert-alert {
    background-color: #f2dede;
    border-color: #eed3d7;
    color: #b94a48;
    text-align: left;
 }

.alert-success {
    background-color: #dff0d8;
    border-color: #d6e9c6;
    color: #468847;
    text-align: left;
 }

.alert-notice {
    background-color: #dff0d8;
    border-color: #d6e9c6;
    color: #468847;
    text-align: left;
 }
Michael Brawn
  • 303
  • 2
  • 9
Daniel
  • 2,950
  • 2
  • 25
  • 45
  • 1
    This looks great for error messages, but what about normal flash messages like "Signed in successfully"? I could define a custom css class .alert-alert for that like you did, but I'd rather have devise name those according to convention of the rest of the site, e.g. 'success' so it would use CSS class .alert-success. There must be another Devise method to override for that -- I'll investigate. – Tony Zito Dec 30 '14 at 20:17
0

I'm guessing since flash[:error].to_a resource.errors.full_messages produces an array which is then simply printed out in your alert through <%= value %>, it prints the entire array which is not what you want.

Instead of printing the array directly, you may want to try looping through the contents like so:

<% value.each do |n| %>
  # Print content here to get desired effect
<% end %>
rawfish.dev
  • 319
  • 3
  • 13
  • You are thinking of putting the loop in the "app/helpers/application_helper.rb" file, in the devise_flash method correct? – Daniel Nov 28 '13 at 18:44
  • @ravensfan55222 actually I meant to place the loop within app/views/layouts/_messages.html.erb to replace `<%= value %>` :) – rawfish.dev Nov 29 '13 at 02:05
  • I see what you mean. When I do <% value.each do |n| %>, it displays an error. Also im really unsure of what to print out. I was thinking I would display it in an unordered list I was trying to add this into the #print content area: "flash.now[:error] = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join" although it didn't display it properly. – Daniel Nov 29 '13 at 05:30
  • I think it would be easier to display the correct error message if I change it in the application_helper because then the message is directly shown through the flash.each do loop. Using "flash.now[:error] = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join", if I can figure out how to use tags in the _messages.html.erb file then I may be able to display it – Daniel Nov 29 '13 at 05:46