Rails: элегантный способ отображения сообщения, когда в базе нет элементов - PullRequest
65 голосов
/ 22 июня 2009

Я понял, что пишу много кода, похожего на этот:

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

Есть ли какая-либо конструкция в Ruby и / или Rails, которая позволила бы мне пропустить это первое условие? Так что будет выполнено, когда итератор / цикл не войдет ни разу? За Пример:

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

Ответы [ 10 ]

159 голосов
/ 05 июня 2010

Вы также можете написать что-то вроде этого:

<% if @messages.each do |message| %>
  <%# code or partial to display the message %>
<% end.empty? %>
  You have no messages.
<% end %>
60 голосов
/ 22 июня 2009

Если вы используете параметр :collection для рендеринга, например, render :partial => 'message', :collection => @messages, тогда вызов render будет возвращать nil, если коллекция пуста. Это может быть включено в || выражение, например

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

Если вы раньше не сталкивались с этим, то render :collection отображает коллекцию, используя один и тот же фрагмент для каждого элемента, делая каждый элемент @messages доступным через локальную переменную message, так как он создает полный ответ. Вы также можете указать разделитель, который будет отображаться между каждым элементом, используя :spacer_template => "message_divider"

16 голосов
/ 09 апреля 2013

Я удивлен, что мой любимый ответ не здесь.Есть ответ, который близок, но мне не нравится голый текст, и использование content_for - клунки.Попробуйте этот размер:

  <%= render(@user.recipes) || content_tag("p") do %>
    This user hasn't added any recipes yet!
  <% end %>
16 голосов
/ 22 июня 2009

Один из способов сделать что-то вроде:

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

Редактировать:

Если я правильно помню, это стало возможным благодаря этому коммиту:

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

6 голосов
/ 22 июня 2009

Вы можете создать своего собственного помощника. Следующий пример - только пример.

# 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 %>
3 голосов
/ 22 июня 2009

Как примечание, вы можете просто перебрать пустой массив, если вы ищете эффективность выражения:

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

Хотя @messages не имеет значения nil, оно должно работать в большинстве ситуаций. Введение нерегулярных расширений в то, что должно быть рутинным представлением, вероятно, усложняет в противном случае простую вещь.

Что может быть лучше, так это определить партиал и помощник для рендеринга «пустых» секций, если они достаточно сложные:

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

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

Где вы можете определить это как:

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
1 голос
/ 24 января 2013

Старая тема, но мне не очень нравилось ни одно из них, поэтому, поиграв на Rails 3.2, я нашел эту альтернативу:

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

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

Или, если вам нужен более подробный рендер с частичным путем, как я сделал:

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

Таким образом, вы можете стилизовать часть «без сообщений» с любой желаемой HTML / логикой представления и сделать ее удобной для чтения.

0 голосов
/ 28 июня 2019

Ниже решение работает для меня, потому что я хочу tr и td с colspan свойством:

<%= render(@audit_logs) || content_tag(:tr, content_tag(:td, 'No records',colspan: "11"))%>
0 голосов
/ 22 июня 2009

Вы можете разделить ваши два дела на разные шаблоны: один, если сообщения существуют, и один, если сообщений нет. В действии контроллера (MessagesController#index, вероятно) добавьте в качестве последнего оператора:

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

Если сообщений нет, будет отображаться app/views/messages/index_empty.html.erb. Если есть сообщения, они будут проваливаться и отображать app/views/messages/index.html.erb как обычно.

Если вам это нужно более чем в одном действии, вы можете приятно преобразовать его в вспомогательный метод, подобный следующему (не проверено):

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

При этом вам просто нужно поставить render_action_or_empty(@var) в конце любого действия контроллера, и он будет отображать либо шаблон 'action', либо шаблон 'action_empty', если ваша коллекция пуста. Также должно быть легко заставить эту работу работать с частями вместо шаблонов действий.

0 голосов
/ 22 июня 2009

Этот код можно сократить до:

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

Комментарии:

formatted_msg () - вспомогательный метод, который добавляет форматирование к сообщению

msg_delimiter - переменная, содержащая разделитель типа "\ n" или "<br />"

Кстати, я бы предложил использовать пустой? метод вместо пустого? для проверки массива, потому что а) его имя более лаконично :) и б) пусто? это метод расширения ActiveSupport, который не будет работать вне Rails.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...