web-dev-qa-db-fra.com

Rails: une manière élégante d'afficher un message lorsqu'il n'y a pas d'éléments dans la base de données

J'ai réalisé que j'écrivais beaucoup de code similaire à celui-ci:

<% unless @messages.blank? %>
  <% @messages.each do |message|  %>
    <%# code or partial to display the message %>
  <% end %>
<% else %>
  You have no messages.
<% end %>

Y a-t-il une construction dans Ruby et/ou Rails qui me permettrait de sauter cette première condition? Donc, cela serait exécuté lorsque l'itérateur/boucle n'entre pas même une fois? Par exemple:

<% @messages.each do |message| %>
  <%# code or partial to display the message %>
<% and_if_it_was_blank %>
  You have no messages.
<% end %>
65
Jakub Troszok

Si vous utilisez le :collection paramètre à rendre par exemple render :partial => 'message', :collection => @messages alors l'appel au rendu retournera nil si la collection est vide. Cela peut ensuite être incorporé dans un || expression par exemple.

<%= render(:partial => 'message', :collection => @messages) || 'You have no messages' %>

Au cas où vous ne l'auriez pas encore rencontré, rendez :collection rend une collection en utilisant le même partiel pour chaque élément, ce qui rend chaque élément de @messages disponible via la variable locale message lors de l'élaboration de la réponse complète. Vous pouvez également spécifier un séparateur à rendre entre chaque élément en utilisant :spacer_template => "message_divider"

60
mikej

Vous pouvez également écrire quelque chose comme ceci:

<% if @messages.each do |message| %>
  <%# code or partial to display the message %>
<% end.empty? %>
  You have no messages.
<% end %>
159
Fernando Allen

Je suis surpris que ma réponse préférée ne soit pas ici. Il y a une réponse qui est proche, mais je n'aime pas le texte nu et utiliser content_for est klunky. Essayez celui-ci pour la taille:

  <%= render(@user.recipes) || content_tag("p") do %>
    This user hasn't added any recipes yet!
  <% end %>
16
David Bock

Une façon est de faire quelque chose comme:

<%= render(:partial => @messages) || render('no_messages') %>

Éditer:

Si je me souviens bien, cela a été rendu possible par ce commit:

http://github.com/Rails/rails/commit/a8ece12fe2ac7838407954453e0d31af6186a5db

16
jonnii

Vous pouvez créer une aide personnalisée. Le suivant n'est qu'un exemple.

# 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 %>
6
Simone Carletti

En guise de note, vous pouvez aussi simplement parcourir un tableau vide si vous recherchez l'efficacité de l'expression:

<% @messages.each do |message|  %>
  <%# code or partial to dispaly the message %>
<% end %>
<% if (@messages.blank?) %>
  You have no messages.
<% end %>

Bien que cela ne gère pas les @messages étant nuls, cela devrait fonctionner dans la plupart des situations. L'introduction d'extensions irrégulières à ce qui devrait être une vue de routine complique probablement une chose par ailleurs simple.

La meilleure approche pourrait être de définir une section partielle et une aide pour rendre les sections "vides" si celles-ci sont raisonnablement complexes:

<% render_each(:message) do |message|  %>
  <%# code or partial to dispaly the message %>
<% end %>

# common/empty/_messages.erb
You have no messages.

Où vous pourriez définir cela comme:

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
3
tadman

Vieux sujet mais je n'aimais vraiment aucun de ceux-ci, alors jouer sur Rails 3.2 J'ai compris cette alternative:

<% content_for :no_messages do %>
  <p>
    <strong>No Messages Found</strong>
  </p>
<% end %>

<%= render @messages || content_for(:no_messages) %>

Ou si vous avez besoin d'un rendu plus détaillé avec un chemin partiel comme je l'ai fait:

<%= render(:partial => 'messages', 
     :collection => @user.messages) || content_for(:no_messages) %>

De cette façon, vous pouvez styliser la partie "pas de messages" avec la logique HTML/vue que vous voulez et la garder facile à lire.

1
Kansha

Vous pouvez diviser vos deux cas en différents modèles: un si des messages existent et un si aucun message n'existe. Dans l'action du contrôleur (MessagesController#index Probablement), ajoutez comme dernière instruction:

render :action => 'index_empty' if @messages.blank?

S'il n'y a pas de message, il affichera app/views/messages/index_empty.html.erb. S'il y a des messages, il tombera et affichera app/views/messages/index.html.erb Comme d'habitude.

Si vous en avez besoin dans plus d'une action, vous pouvez la refactoriser en une méthode d'assistance comme celle-ci (non testée):

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

Avec cela, il vous suffit de mettre render_action_or_empty(@var) à la fin de toute action du contrôleur et il affichera soit le modèle 'action' ou le modèle 'action_empty' si votre collection est vide. Il devrait également être facile de faire fonctionner cela avec des partiels au lieu de modèles d'action.

0
Zargony

La solution ci-dessous fonctionne pour moi car je veux tr et td avec la propriété colspan:

<%= render(@audit_logs) || content_tag(:tr, content_tag(:td, 'No records',colspan: "11"))%>
0
Jigar Bhatt

Ce code peut être abrégé en:

<%= @messages.empty? ? 'You have no messages.' : @messages.collect { |msg| formatted_msg(msg) }.join(msg_delimiter) %>

Commentaires:

formatted_msg () - méthode d'assistance qui ajoute une mise en forme au message

msg_delimiter - variable contenant un délimiteur comme "\ n" ou "<br /> "

BTW je suggère d'utiliser vide? méthode au lieu de blanc? pour vérifier un tableau, car a) son nom est plus concis :) et b) vide? est une méthode d'extension ActiveSupport qui ne fonctionnera pas en dehors de Rails.

0
Lukas Stejskal