-
Notifications
You must be signed in to change notification settings - Fork 0
12b Flash Refactoring
I don't know about you, but I hate having all that flash message logic in the layout.
app/views/layouts/application.html.erb
<% flash.each do |name, msg| -%>
<% if msg.is_a? Array -%>
<div class="<%= name %>">
<ul>
<% msg.each do |message| -%>
<li><%= message %></li>
<% end -%>
</ul>
</div>
<% else -%>
<%= content_tag :div, msg, class: name %>
<% end -%>
<% end -%>
Wouldn't it be nice if we could replace all that with this:
<%= flash_messages(flash) unless flash.empty? %>
We can make that happen if we build out that flash_messages
helper. I'm going to work from the inside out, and first define a method to replace just this part:
<ul>
<% msg.each do |message| -%>
<li><%= message %></li>
<% end -%>
</ul>
We'll create the li
elements with a content_tag
and nest it inside another content_tag
for the ul
.
app/helpers/application_helper.rb
def flash_list(messages)
content_tag :ul do
messages.map do |message|
content_tag(:li, message)
end.join.html_safe
end
end
We'll use Enumerator#map
to collect all of the li
elements in an array. At the end, we'll join them into a string.
When we return the resulting string, we need to prevent Rails from escaping the HTML inside. That's where html_safe
comes in. When we use content_tag
by itself, this isn't necessary, but because our string was built from an array, and not directly from content_tag
, we need html_safe
.
Now let's replace that giant if
statement.
<% if msg.is_a? Array -%>
<div class="<%= name %>">
<ul>
<% msg.each do |message| -%>
<li><%= message %></li>
<% end -%>
</ul>
</div>
<% else -%>
<%= content_tag :div, msg, class: name %>
<% end -%>
We'll create another helper method.
app/helpers/application_helper.rb
def flash_message_output(content)
if content.is_a? Array
flash_list content
else
content
end
end
If the content supplied to flash_message_output
, we'll call the flash_list
method we wrote a moment ago. Otherwise, we just return the content itself.
Now let's write the actual flash_messages
method to output the entire div
. From this method, we'll call the flash_message_output
method we just wrote.
app/helpers/application_helper.rb
def flash_messages(flash)
flash.map do |name, msg|
content_tag :div, class: "alert #{name}" do
flash_message_output msg
end
end.join.html_safe
end
Now that single line in our layout does the work of that whole big mess. I like this version much better!
If you're into it, commit it!
$ git add .
$ git commit -m "Extract flash into helper methods."