Rails中如何合并ActiveRecord关联查询结果实现统一遍历
问题场景
Skill模型需要为业务提供两类关联值集合:
- 第一类来自Skill直接绑定的主ValuesList对象
- 第二类来自通过多对多关系关联的、承载质量类补全值的额外ValuesList对象
现有模型定义
class Value < ApplicationRecord belongs_to :values_list end class ValuesList < ApplicationRecord has_many :values, inverse_of: :values_list, dependent: :delete_all has_many :skills # 缺失答案的质量类补全值关联 has_many :skills_values_lists, foreign_key: "values_list_id" has_many :referents, class_name: "Skill", through: :skills_values_lists end class Skill < ApplicationRecord belongs_to :values_list # 缺失答案的质量类补全值关联 has_many :skills_values_lists, foreign_key: "skill_id" has_many :references, class_name: "ValuesList", through: :skills_values_lists accepts_nested_attributes_for :skills_values_lists, reject_if: :all_blank, allow_destroy: true end
当前查询的问题
现有查询写法的返回值结构不统一:
- 查询常规值:
@regular_values = @skill.values_list.values
返回ActiveRecord::Associations::CollectionProxy类型对象,可直接遍历 - 查询额外值:
@extra_values = @skill.references.map {|vl| vl.values}
返回嵌套数组,数组内的元素是多个关联代理对象,无法直接统一遍历所有值
合并方案
快速适配方案(适合小数据量场景)
直接将两类查询结果打平为统一的Value实例数组,即可直接用.each遍历:
@all_values = @regular_values.to_a + @extra_values.flatten
缺点:会触发N+1次数据库查询,且加载到内存后无法再执行数据库层面的筛选、排序、分页操作
性能优化方案(适合正式生产场景)
在Skill模型中封装统一的查询方法,返回标准的ActiveRecord::Relation对象,避免N+1查询:
- 在Skill模型中新增统一查询方法:
def all_associated_values # 合并主ValuesList、所有关联额外ValuesList下的所有Value Value.where(values_list: self.values_list) .or(Value.where(values_list: self.references)) end - 调用时直接获取统一可操作的对象:
该返回值既可以直接通过@all_values = @skill.all_associated_values.each循环遍历展示,也支持后续的排序、筛选、分页等数据库操作,仅需2次关联查询即可拿到所有数据。
内容的提问来源于stack exchange,提问作者user1185081
相关产品推荐
相关产品推荐

