Rails:在数据库中没有元素时显示消息的优雅方式

时间:2009-06-22 15:33:43

标签: ruby-on-rails ruby loops iterator

我意识到我正在编写许多与此类似的代码:

<% 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 个答案:

答案 0 :(得分:159)

你也可以这样写:

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

答案 1 :(得分:60)

如果您使用: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 :(得分:16)

一种方法是做一些事情:

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

编辑:

如果我没记错的话,这可以通过这个提交来实现:

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

答案 3 :(得分:16)

我很惊讶我最喜欢的答案不在这里。有一个答案很接近,但我不喜欢裸文,使用content_for是笨拙的。试试这个尺寸:

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

答案 4 :(得分:6)

您可以创建一些自定义帮助程序。以下是一个例子。

# 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 %>

答案 5 :(得分:3)

作为一个注释,如果你正在寻找表达效率,你也可以迭代一个空数组:

<% @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

答案 6 :(得分:1)

老话题,但我真的不喜欢其中的任何一个,所以在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 /视图逻辑设置“无消息”部分的样式,并使其易于阅读。

答案 7 :(得分:0)

该代码可以缩短为:

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

评论:

formatted_msg() - 为消息添加格式的辅助方法

msg_delimiter - 包含分隔符的变量,如“\ n”或“<br />

BTW我建议用空?方法而不是空白?用于检查数组,因为a)它的名称更简洁:)和b)空白?是一个ActiveSupport扩展方法,它不能在Rails之外工作。

答案 8 :(得分:0)

您可以将两个案例分成不同的模板:一个是邮件存在,另一个是不存在邮件。在控制器操作中(可能是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'模板。使用partials而不是动作模板也可以很容易地使用它。

答案 9 :(得分:0)

以下解决方案对我有用,因为我想要trtd具有colspan属性:

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