Rails: An elegant way to display a message when there are no elements in database
Solution 1
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"
Solution 2
You could also write something like this:
<% if @messages.each do |message| %>
<%# code or partial to display the message %>
<% end.empty? %>
You have no messages.
<% end %>
Solution 3
I'm surprised my favorite answer isn't up here. There is an answer thats close, but I don't like bare text and using content_for is klunky. Try this one on for size:
<%= render(@user.recipes) || content_tag("p") do %>
This user hasn't added any recipes yet!
<% end %>
Solution 4
One way is to do something like:
<%= render(:partial => @messages) || render('no_messages') %>
Edit:
If I remember correctly this was made possible by this commit:
http://github.com/rails/rails/commit/a8ece12fe2ac7838407954453e0d31af6186a5db
Solution 5
You can create some custom helper. The following one is just an example.
# application_helper.html.erb
def unless_empty(collection, message = "You have no messages", &block)
if collection.empty?
concat(message)
else
concat(capture(&block))
end
end
# view.html.erb
<% unless_empty @messages do %>
<%# code or partial to dispaly the message %>
<% end %>
Comments
-
Jakub Troszok almost 4 years
I realized that I'm writing a lot of code similar to this one:
<% unless @messages.blank? %> <% @messages.each do |message| %> <%# code or partial to display the message %> <% end %> <% else %> You have no messages. <% end %>
Is there any construct in Ruby and/or Rails that would let me skip that first condition? So that would be executed when iterator/loop won't enter even once? For example:
<% @messages.each do |message| %> <%# code or partial to display the message %> <% and_if_it_was_blank %> You have no messages. <% end %>
-
Jakub Troszok almost 15 yearsThanks for suggesion but I prefer to use blank? because i don't have to check if object is not nil, and being only rails specific extension doesn't bother me much in this case.
-
mataal almost 15 yearsgreat... how about a before collection and after collection? say you want to have <ul> and </ul> or <tr></tr> tag pairs before and after the partial rendering but only if the @messages ar enot empty. examples- > <p><ul><li>message1</li><message2></ul><p> is @messages!=nil OR <p><ul>no messages!<p>
-
arikfr over 13 yearsI think that Fernando Allen's solution should be added to this answer as possible alternative, as people might skip it because it's not the "best answer".
-
James F over 12 yearsI love this answer. I used this one out of all myself, super clean and very understandable.
-
pruett almost 12 yearsjust a quick note that may be helpful. in order for this syntax to work, you must use parentheses around the
partial
assignment as shown above. without them, the partial renders correctly, but the conditional message does not -
dkubb over 10 yearsThis is my favourite answer so far.
-
Shane about 10 yearsAwesome answer, very succinct.
-
DickieBoy over 9 yearsHow would you do something like this in haml/slim?
-
user435779 over 9 yearsThanks! The accepted answer is more Rails-y (and probably should be the accepted answer for exactly that reason), but this one is going to save me a lot of time while I build a prototype.
-
D-side over 9 yearsImportant: don't forget parentheses for
render
, otherwise the||
will apply not to the result ofrender
, but to the collection itself. I've just written the same myself, but it didn't work (at first) because of this. -
onmyway133 over 9 yearsWhat is this feature called?
-
markquezada over 8 yearsThis was the elegant solution I was looking for :)
-
mArtinko5MB over 3 yearsthis is exactly what i was looking for!