Rails: An elegant way to display a message when there are no elements in database

20,009

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 %>
Share:
20,009
Jakub Troszok
Author by

Jakub Troszok

I do sitting in front of a computer for living...

Updated on June 28, 2020

Comments

  • Jakub Troszok
    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
    Jakub Troszok almost 15 years
    Thanks 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
    mataal almost 15 years
    great... 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
    arikfr over 13 years
    I 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
    James F over 12 years
    I love this answer. I used this one out of all myself, super clean and very understandable.
  • pruett
    pruett almost 12 years
    just 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
    dkubb over 10 years
    This is my favourite answer so far.
  • Shane
    Shane about 10 years
    Awesome answer, very succinct.
  • DickieBoy
    DickieBoy over 9 years
    How would you do something like this in haml/slim?
  • user435779
    user435779 over 9 years
    Thanks! 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
    D-side over 9 years
    Important: don't forget parentheses for render, otherwise the || will apply not to the result of render, but to the collection itself. I've just written the same myself, but it didn't work (at first) because of this.
  • onmyway133
    onmyway133 over 9 years
    What is this feature called?
  • markquezada
    markquezada over 8 years
    This was the elegant solution I was looking for :)
  • mArtinko5MB
    mArtinko5MB over 3 years
    this is exactly what i was looking for!