如何在ERB中遍历Rails的has_many :through关联且不产生重复内容
问题原因
- 核心原因是
has_many :through关联默认不会自动去重:你当前Section和同一个Category之间有N条Post关联记录,调用s.categories时就会返回N个完全相同的Category对象,遍历的时候自然会重复输出N次,重复次数和Post数量完全对应。 - 次要问题是控制器逻辑不符合Rails规范:Section详情页不需要查询全量
Section.all再在视图层判断路径匹配,属于不必要的冗余逻辑,也会带来额外的性能开销。
解决方案
第一步:修复关联定义自动去重
修改Section模型中的categories关联,添加去重约束:
class Section < ApplicationRecord has_many :posts # 加 -> { distinct } 让关联查询自动去重 has_many :categories, -> { distinct }, through: :posts has_rich_text :description def to_param url end end
修改后调用@section.categories只会返回不重复的分类对象,直接解决重复输出问题。
第二步:优化控制器逻辑(符合Rails规范)
Section详情页对应的控制器方法(一般是sections_controller.rb的show方法)直接查询单个Section对象即可,不需要查全量数据:
class SectionsController < ApplicationController def show # 因为你重写了to_param用url字段作为路由参数,所以用url查询 @section = Section.find_by!(url: params[:id]) end end
第三步:简化视图代码
去掉冗余的全量Section遍历和路径判断逻辑,直接使用控制器查询到的单个@section对象:
<% @section.categories.each do |c| %> <h1><%= c.title %></h1> <p><%= c.description %></p> <% # 只取当前Section下属于该分类的Post,避免拿到其他Section的同分类Post %> <% c.posts.where(section: @section).each do |p| %> <%= p.title %> <% end %> <% end %>
补充说明
如果你不想修改关联定义,也可以在视图查询时临时去重,写法为<% s.categories.distinct.each do |c| %>,但推荐直接修改关联定义,后续所有调用该关联的地方都会自动生效,无需重复写去重逻辑。
内容的提问来源于stack exchange,提问作者G. F. Hopper
相关产品推荐
相关产品推荐

