Ruby on Rails has a special object called flash which hold its contents for one more request. It’s particularly useful to show messages after a redirect. Since it’s good style to redirect after each succesful form post, that’s where you put the messages such as: “You’ve logged in”, “Thank you for your feedback”, “The book has been added”, etc.
This flash object looks like a hash table. I normally use two items in there: notice, for good stuff and errors, for bad stuff. I want these messages to be displayed in all pages, so whenever something bad or good happens, I just drop stuff in the notice or error and forget about it. This is trivial to do, I just put this:
<% if flash[:error] -%> <p class='error'><%=h flash[:error] %></p> <% end -%> <% if flash[:notice] -%> <p class='notice'><%=h flash[:notice] %></p> <% end -%>
on the application layout.
The problem with doing that is that it doesn’t look nice. I expect error messages and success messages to be near the forms or UI elements I’m interacting with. That means that every view or page will put it in a different location. No problem, you just add that same snippet where you want the messages to appear.
Then there’s a second problem: you get messages twice. If you remove them from the application layout, then you have to remember to put in absolutely every view, even those that you don’t expect to never show an error or notice. I don’t trust myself to always remember to do anything, so what happens is that I can’t just drop something in the flash and expected it to be show, I have to check every time.
I’m doing this in for a pet projects with less than 10 views, but I think big. I think of the project having 100 views and three coders than don’t know all the implicit rules, like adding the display message snippet to every view they create.
I’ve came up with this solution. I created a partial view with this content:
<% if not @messages_rendered -%> <% if flash[:error] -%> <p class='error'><%=h flash[:error] %></p> <% end -%> <% if flash[:notice] -%> <p class='notice'><%=h flash[:notice] %></p> <% end -%> <% end -%> <% @messages_rendered = true -%>
That partial view is rendered from the views and also from the application layout, but it displays the messages only once. Thankfully Rails renders the partials inside the views first, so that the messages gets displayed according to the view, and if the view didn’t display them, the application layout will.