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

后端 未结 10 1029
花落未央
花落未央 2020-12-04 09:51

I realized that I\'m writing a lot of code similar to this one:

<% unless @messages.blank? %>
  <% @messages.each do |message|  %>
    <%# cod         


        
相关标签:
10条回答
  • 2020-12-04 10:21

    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.

    0 讨论(0)
  • 2020-12-04 10:22

    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"))%>
    
    0 讨论(0)
  • 2020-12-04 10:26

    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"

    0 讨论(0)
  • 2020-12-04 10:26

    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
    
    0 讨论(0)
提交回复
热议问题