Ruby on Rails视图中集合前后对象属性访问报错的解决方法
问题分析
报错的核心原因是:当遍历到集合的最后一个元素时,index.succ会返回超出集合最大索引的数值(比如集合长度为5,最后一个元素索引是4,succ后得到5),此时@gallery[index.succ]返回nil,调用nil.id自然触发undefined method 'id' for nil:NilClass。同理,若你用index.pred获取前一个元素,当遍历第一个元素时,index.pred得到-1,@gallery[-1]会返回集合最后一个元素(这不符合你要的“前一个项目”逻辑)。
正确解决方法
要实现顺序的前后项目链接(第一个元素无前链接、最后一个元素无后链接),需要先判断前后元素是否存在,再访问属性,具体有两种常用方式:
方式1:基于索引判断存在性(推荐)
遍历集合时,通过索引范围直接判断前后元素是否存在,避免拿到nil或错误元素:
<% @gallery.each_with_index do |current_item, index| %> <% # 获取前一个元素:索引大于0时才存在 %> <% prev_item = index > 0 ? @gallery[index - 1] : nil %> <% # 获取后一个元素:索引小于集合最大索引时才存在 %> <% next_item = index < @gallery.size - 1 ? @gallery[index + 1] : nil %> <!-- 前一个链接:仅存在时渲染 --> <% if prev_item %> <a href="#lightbox-<%= prev_item.id %>" class="lightbox-prev">上一张</a> <% end %> <!-- 当前灯箱元素 --> <div id="lightbox-<%= current_item.id %>" class="lightbox-content"> <!-- 内容示例:<%= image_tag current_item.image.url %> --> </div> <!-- 后一个链接:仅存在时渲染 --> <% if next_item %> <a href="#lightbox-<%= next_item.id %>" class="lightbox-next">下一张</a> <% end %> <% end %>
方式2:使用Ruby安全导航符简化判断
如果不想写显式的if判断,可以用Ruby的安全导航操作符&.,它会在对象为nil时直接返回nil,避免触发方法调用错误:
<% @gallery.each_with_index do |current_item, index| %> <% prev_item = index > 0 ? @gallery[index - 1] : nil %> <% next_item = index < @gallery.size - 1 ? @gallery[index + 1] : nil %> <a href="#lightbox-<%= prev_item&.id %>" class="lightbox-prev" <%= 'style="display: none;"' unless prev_item %>>上一张</a> <div id="lightbox-<%= current_item.id %>" class="lightbox-content"> <!-- 内容 --> </div> <a href="#lightbox-<%= next_item&.id %>" class="lightbox-next" <%= 'style="display: none;"' unless next_item %>>下一张</a> <% end %>
额外提示:循环灯箱实现
如果需要实现循环灯箱(最后一个元素的后链接指向第一个,第一个元素的前链接指向最后一个),可以这样处理:
<% @gallery.each_with_index do |current_item, index| %> <% prev_index = index == 0 ? @gallery.size - 1 : index - 1 %> <% next_index = index == @gallery.size - 1 ? 0 : index + 1 %> <% prev_item = @gallery[prev_index] %> <% next_item = @gallery[next_index] %> <a href="#lightbox-<%= prev_item.id %>" class="lightbox-prev">上一张</a> <div id="lightbox-<%= current_item.id %>" class="lightbox-content"> <!-- 内容 --> </div> <a href="#lightbox-<%= next_item.id %>" class="lightbox-next">下一张</a> <% end %>
内容的提问来源于stack exchange,提问作者Jerome
相关产品推荐
相关产品推荐

