-
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
endWe'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
endIf 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
endNow 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."