Rails: элегантный способ отображения сообщения, когда в базе данных нет элементов
Я понял, что я пишу много кода, подобного этому:
<% 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 %>
Ответы
Ответ 1
Если вы используете параметр :collection
для рендеринга, например. render :partial => 'message', :collection => @messages
, тогда вызов render вернет nil
, если коллекция пуста. Это может быть затем включено в || выражение, например.
<%= render(:partial => 'message', :collection => @messages) || 'You have no messages' %>
Если вы не встретили его раньше, рендер :collection
отображает коллекцию с использованием того же частичного для каждого элемента, что делает каждый элемент @messages
доступным через локальную переменную message
, поскольку она создает полную ответ. Вы также можете указать разделитель, который будет отображаться между каждым элементом, используя :spacer_template => "message_divider"
Ответ 2
Вы также можете написать что-то вроде этого:
<% if @messages.each do |message| %>
<%# code or partial to display the message %>
<% end.empty? %>
You have no messages.
<% end %>
Ответ 3
Один из способов - сделать что-то вроде:
<%= render(:partial => @messages) || render('no_messages') %>
Изменить:
Если я правильно помню, это стало возможным благодаря этой фиксации:
http://github.com/rails/rails/commit/a8ece12fe2ac7838407954453e0d31af6186a5db
Ответ 4
Я удивлен, что мой любимый ответ здесь не здесь. Есть ответ, который близко, но мне не нравится голосовой текст и использование content_for является klunky. Попробуйте этот вариант для размера:
<%= render(@user.recipes) || content_tag("p") do %>
This user hasn't added any recipes yet!
<% end %>
Ответ 5
Вы можете создать некоторый пользовательский помощник. Следующий пример - это просто пример.
# 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
В качестве примечания вы можете просто перебрать пустой массив, если вы ищете эффективность выражения:
<% @messages.each do |message| %>
<%# code or partial to dispaly the message %>
<% end %>
<% if (@messages.blank?) %>
You have no messages.
<% end %>
Хотя это не обрабатывает @messages, равное нулю, оно должно работать в большинстве ситуаций. Введение нерегулярных расширений в то, что должно быть обычным видом, вероятно, усложняет простую вещь.
Что может быть лучшим подходом, так это определить частичный и вспомогательный для визуализации "пустых" разделов, если они достаточно сложны:
<% 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
Ответ 7
Старая тема, но мне не очень понравилось, что они так играли на 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/вида, которую вы хотите, и сохранить ее в удобной для чтения.
Ответ 8
Этот код можно сократить до:
<%= @messages.empty? ? 'You have no messages.' : @messages.collect { |msg| formatted_msg(msg) }.join(msg_delimiter) %>
Комментарии:
formatted_msg() - вспомогательный метод, который добавляет форматирование в сообщение
msg_delimiter - переменная, содержащая разделитель типа "\n" или "<br />
"
Кстати, я предлагаю использовать пустые? вместо пустой? для проверки массива, потому что а) его имя более кратким:) и б) пустым? это метод расширения ActiveSupport, который не будет работать за пределами Rails.
Ответ 9
Вы можете разделить свои два случая на разные шаблоны: один, если существуют сообщения, и один, если сообщение отсутствует. В действии контроллера (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_empty", если ваша коллекция пуста. Также должно быть легко сделать эту работу с частичными, а не с шаблонами действий.
Ответ 10
Ниже решение работает для меня, потому что я хочу tr
и td
со свойством colspan
:
<%= render(@audit_logs) || content_tag(:tr, content_tag(:td, 'No records',colspan: "11"))%>