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 %>
9 ответов:
если вы используете для отображения, например,
render :partial => 'message', :collection => @messages
тогда вызов рендеринга вернетсяnil
если коллекция пуста. Затем это может быть включено в выражение|/, например<%= render(:partial => 'message', :collection => @messages) || 'You have no messages' %>
в случае, если вы не сталкивались с этим раньше, оказывать
:collection
отображает коллекцию с использованием одного и того же частичного для каждого элемента, делая каждый элемент@messages
доступно через локальную переменнуюmessage
как он строит полный ответ. Вы также можете указать разделитель для быть визуализированы между каждым элементом с помощью:spacer_template => "message_divider"
вы также могли написать что-то вроде этого:
<% if @messages.each do |message| %> <%# code or partial to display the message %> <% end.empty? %> You have no messages. <% end %>
один из способов-это сделать что-то вроде:
<%= render(:partial => @messages) || render('no_messages') %>
Edit:
Если я правильно помню, это стало возможным благодаря этой фиксации:
http://github.com/rails/rails/commit/a8ece12fe2ac7838407954453e0d31af6186a5db
Я удивлен, что мой любимый ответ не здесь. Есть ответ, который близок, но мне не нравится голый текст и использование content_for является неуклюжим. Попробуйте это на размер:
<%= render(@user.recipes) || content_tag("p") do %> This user hasn't added any recipes yet! <% end %>
вы можете создать пользовательский помощник. Следующий пример-это просто пример.
# 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 %>
как Примечание, Вы можете также просто перебирать пустой массив, если вы ищете эффективность выражения:
<% @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
старая тема, но мне не очень понравилось ни одно из них, поэтому, играя на 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 / view, которую вы хотите, и сохранить ее приятной для чтения.
этот код можно сократить до:
<%= @messages.empty? ? 'You have no messages.' : @messages.collect { |msg| formatted_msg(msg) }.join(msg_delimiter) %>
комментарии:
formatted_msg () - вспомогательный метод, который добавляет форматирование к сообщению
msg_delimiter-переменная, содержащая разделитель типа "\n "или"
<br />
"кстати, я бы предложил использовать пустые? метод вместо пустого? для проверки массива, потому что а) его имя более сжато:) и Б) пустое? это метод расширения ActiveSupport, который не будет работать вне рельсов.
вы можете разделить ваши два случая на разные шаблоны: один, если сообщения существуют и один, если сообщения не существуют. В действии контроллера (
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", если ваша коллекция пуста. Это также должно быть легко сделать эту работу с частичными данными вместо шаблонов действий.