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 %>
如果使用:collection
参数来渲染,例如render :partial => 'message', :collection => @messages
那么如果集合是空的,那么对render的调用将返回nil
。 这可以被合并到一个||中 expression例如
<%= render(:partial => 'message', :collection => @messages) || 'You have no messages' %>
如果您之前没有遇到过,render :collection
会为每个元素使用相同的部分来呈现一个集合,当它构build完整的响应时,通过局部variablesmessage
使每个@messages
元素可用。 您还可以使用以下命令指定要在每个元素之间呈现的分隔线: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') %>
编辑:
如果我没有记错的话,这个提交就成了可能:
http://github.com/rails/rails/commit/a8ece12fe2ac7838407954453e0d31af6186a5db
我很惊讶,我最喜欢的答案不在这里。 有一个答案是closures的,但我不喜欢裸文本和使用content_for是klunky。 尝试这一个大小:
<%= render(@user.recipes) || content_tag("p") do %> This user hasn't added any recipes yet! <% end %>
你可以创build一些自定义帮手。 下面的只是一个例子。
# 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 %>
作为一个说明,如果你正在寻找expression效率,你可能只是遍历一个空的数组:
<% @messages.each do |message| %> <%# code or partial to dispaly the message %> <% end %> <% if (@messages.blank?) %> You have no messages. <% end %>
虽然这不处理@消息为零,它应该适用于大多数情况。 引入不规则扩展到常规视图可能会使一个简单的事情复杂化。
可能更好的方法是定义一个部分和一个帮助器来渲染“空白”部分,如果这些部分是相当复杂的:
<% 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上玩耍我想出了这个替代scheme:
<% content_for :no_messages do %> <p> <strong>No Messages Found</strong> </p> <% end %> <%= render @messages || content_for(:no_messages) %>
或者如果你需要像我这样部分path的更详细的渲染:
<%= render(:partial => 'messages', :collection => @user.messages) || content_for(:no_messages) %>
通过这种方式,您可以使用任何HTML /视图逻辑来设置“无消息”部分的样式,并使其易于阅读。
该代码可以缩短为:
<%= @messages.empty? ? 'You have no messages.' : @messages.collect { |msg| formatted_msg(msg) }.join(msg_delimiter) %>
注释:
formatted_msg() – 为消息添加格式的辅助方法
msg_delimiter – 包含分隔符(如“\ n”或“ <br />
”)的variables
顺便说一句我会build议使用空? 方法而不是空白? 检查一个数组,因为a)它的名字更简洁:)和b)空白? 是一个ActiveSupport扩展方法,它不会在Rails之外工作。
你可以将你的两个案例分成不同的模板:一个是消息存在,一个是消息不存在。 在控制器动作( MessagesController#index
大概)中,添加为最后一个语句:
render :action => 'index_empty' if @messages.blank?
如果没有消息,它将显示app/views/messages/index_empty.html.erb
。 如果有消息,它会像往常一样通过并显示app/views/messages/index.html.erb
。
如果你不只需要一个动作就需要这个,你可以很好地将它重构成一个像下面这样的辅助方法(未经testing):
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而不是action模板也应该很容易。