I realized that I\'m writing a lot of code similar to this one:
<% unless @messages.blank? %>
<% @messages.each do |message| %>
<%# cod
You could split up your two cases into different templates: one if messages exist and one if no message exist. In the controller action (MessagesController#index
probably), add as the last statement:
render :action => 'index_empty' if @messages.blank?
If there are no messages, it'll display app/views/messages/index_empty.html.erb
. If there are messages, it'll fall through and display app/views/messages/index.html.erb
as usual.
If you need this in more than just one action, you can nicely refactor it into a helper method like the following (untested):
def render_action_or_empty (collection, options = {})
template = params[:template] || "#{params[:controller]}/#{params[:action]}"
template << '_empty' if collection.blank?
render options.reverse_merge { :template => template }
end
With this, you just need to put render_action_or_empty(@var)
at the end of any controller action and it'll display either the 'action' template or the 'action_empty' template if your collection is empty. It should also be easy to make this work with partials instead of action templates.
Below solution works for me because I want tr
and td
with colspan
property:
<%= render(@audit_logs) || content_tag(:tr, content_tag(:td, 'No records',colspan: "11"))%>
If you use the :collection
parameter to render e.g. render :partial => 'message', :collection => @messages
then the call to render will return nil
if the collection is empty. This can then be incorporated into an || expression e.g.
<%= render(:partial => 'message', :collection => @messages) || 'You have no messages' %>
In case you haven't come across it before, render :collection
renders a collection using the same partial for each element, making each element of @messages
available through the local variable message
as it builds up the complete response. You can also specify a divider to be rendered in between each element using :spacer_template => "message_divider"
As a note, you may as well just iterate over an empty array if you're looking for efficiency of expression:
<% @messages.each do |message| %>
<%# code or partial to dispaly the message %>
<% end %>
<% if (@messages.blank?) %>
You have no messages.
<% end %>
While this does not handle @messages being nil, it should work for most situations. Introducing irregular extensions to what should be a routine view is probably complicating an otherwise simple thing.
What might be a better approach is to define a partial and a helper to render "empty" sections if these are reasonably complex:
<% render_each(:message) do |message| %>
<%# code or partial to dispaly the message %>
<% end %>
# common/empty/_messages.erb
You have no messages.
Where you might define this as:
def render_each(item, &block)
plural = "#{item.to_s.pluralize}"
items = instance_variable_get("@#{plural}")
if (items.blank?)
render(:partial => "common/empty/#{plural}")
else
items.each(&block)
end
end