修复Ruby Blacklight视图rdf.fedora.hasPart为空时UI显示异常
问题根因
报错是典型的Ruby空值调用方法异常:当Solr返回的文档没有rdf.fedora.hasPart字段时,@document["rdf.fedora.hasPart"]会返回nil,直接对nil调用each会抛出NoMethodError;就算字段存在,如果值是空字符串、数字这类非可枚举类型,一样会触发页面渲染失败。
解决方案
在ERB视图层遍历前增加值合法性校验即可,有两种常用实现,可根据自己的编码习惯选择:
方案1:前置判断(可读性强,适合新手)
在执行循环前先判断字段存在、值为可遍历的非空集合,满足条件才渲染循环内的内容,修改后的ORAL HISTORY区块代码如下:
<!-- ORAL HISTORY --> <% elsif document.id =~/oh/ %> <iframe src="/pdfjs/web/viewer.html?file=%2Fdocpdfview%2F<%=@document.id%>" allowfullscreen webkitallowfullscreen style="width: 100%; height: 640px"></iframe> <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Download</button> <div class="dropdown-menu"> <a class="dropdown-item" target="_blank" href="/pdfdownload/<%=@document.id%>">PDF</a> <a class="dropdown-item" target="_blank" href="/txt/<%=@document.id%>">Plain Text</a> <a class="dropdown-item" target="_blank" href="/dc/<%=@document.id%>">Metadata (Dublin Core)</a> </div> <video id="videoarea" controls="controls" poster="" src=""></video> <%# 提前把字段值存到局部变量,避免重复从Solr文档取值 %> <% has_part_items = @document["rdf.fedora.hasPart"] %> <%# 校验值为数组类型且非空才执行遍历 %> <% if has_part_items.is_a?(Array) && has_part_items.any? %> <% has_part_items.each do |item| %> <ul class="playlist"> <li movieurl="/mp3/<%=item%>"><%=item%></li> </ul> <% end %> <br><br> <% has_part_items.each do |item| %> <%=item%> <div class="preview_image" align="left"> <video class="video-js vjs-fluid vjs-default-skin" controls="" data-setup='{ "aspectRatio":"640:120"}' playsinline="" poster="/pageturnerserver/ajaxp?theurl=http://localhost:8080/fedora/get/<%=@document.id%>/Preview" preload="none"> <source src="/mp3/<%=item%>" type="video/mp4"> </video> </div> <% end %> <% end %> <!-- AUDIO --> <% elsif document.id =~/aud/ %> <div class="preview_image" align="left"> <video class="video-js vjs-fluid vjs-default-skin" controls="" data-setup='{ "aspectRatio":"640:120"}' playsinline="" poster="/pageturnerserver/ajaxp?theurl=http://localhost:8080/fedora/get/<%=@document.id%>/Preview" preload="none"> <source src="/mp3/<%=@document.id%>" type="video/mp4"> </video> </div>
校验逻辑做了两层防护:
- 先判断值是
Array类型:Solr多值字段默认返回数组格式,这层可以避免字段存了字符串、数字等非可枚举值时触发报错 - 再用
any?判断数组非空:空数组遍历虽然不会报错,但会生成无意义的空DOM标签,加这层判断可以精简输出的HTML
方案2:安全遍历(代码更简洁)
如果不想写冗长的前置判断,可以直接用Ruby内置的Array()方法做兜底转换,一行就能兼容所有空值场景:
<%# Array()会自动把nil、非数组值转成合法数组,永远不会触发遍历报错 %> <% Array(@document["rdf.fedora.hasPart"]).each do |item| %> <ul class="playlist"> <li movieurl="/mp3/<%=item%>"><%=item%></li> </ul> <% end %>
Array()是Ruby内核自带的类型转换方法:传入nil时返回空数组,传入数组时直接返回原数组,传入单值时自动把单值包装成单元素数组,完全覆盖Solr字段可能返回的所有值类型。
额外优化提示
- 现有代码两次遍历同一个
rdf.fedora.hasPart字段,可以合并成一次循环,减少重复逻辑 - HTML规范要求id属性全局唯一,循环内给每个ul加
id="playlist"会生成重复ID,建议改成class属性
内容的提问来源于stack exchange,提问作者Calvin
相关产品推荐
相关产品推荐

