Rails Active Record查询:如何筛选关联全部指定分类ID的视频
解决方法
你当前的scope实现的是「匹配任意一个选中分类」的OR逻辑,要实现「同时匹配所有选中分类」的AND逻辑,推荐用分组统计+条件过滤的方案,兼容绝大多数数据库,性能表现稳定。
1. 修改video.rb中的scope代码
scope :for_categories, -> (category_ids) { # 选中分类为空时直接返回全量视频,避免异常查询 return all if category_ids.blank? target_category_ids = category_ids.uniq joins(:video_categories) .where(video_categories: { category_id: target_category_ids }) .group('videos.id') # 统计每个视频匹配到的不重复分类数,等于选中分类总数才符合要求 .having('COUNT(DISTINCT video_categories.category_id) = ?', target_category_ids.length) }
2. 优化控制器参数处理
表单提交多选参数时会默认带空字符串值,建议先过滤再传入scope:
def search # 过滤掉空值的分类ID cleaned_category_ids = params[:category_ids].to_a.reject(&:blank?) @results = Video.for_categories(cleaned_category_ids) end
逻辑验证
以你给出的示例数据测试:
选中分类ID为[1,7]时,target_category_ids长度为2:
- 视频A匹配到分类1、7,统计得到不重复分类数为2,符合条件
- 视频B匹配到分类1、7,统计得到不重复分类数为2,符合条件
- 视频C仅匹配到分类7,统计得到不重复分类数为1,不符合条件
返回结果正好是你预期的视频A、视频B。
内容的提问来源于stack exchange,提问作者Gregory280
相关产品推荐
相关产品推荐

