Rails 6.1:如何检查查询作用域中已关联的关联关系及别名?
Rails 6.1.7.3 判断关联是否已关联及获取关联别名
判断关联是否已被关联
Rails ActiveRecord查询对象没有直接提供检查关联是否已join的内置方法,但可以通过解析查询对象的joins_values属性实现需求:
- 无别名的直接关联:直接检查
joins_values中是否包含目标关联的符号或字符串
scope = MyModel.where(...) scope.joins!(:assoc) # 判断:assoc是否已join scope.joins_values.include?(:assoc)
- 嵌套关联:检查
joins_values中的哈希结构是否包含目标关联键
scope.joins!(assoc: :nested_assoc) scope.joins_values.any? { |v| v.is_a?(Hash) && v.key?(:assoc) }
- 自定义SQL带别名的关联:解析
joins_values中的SQL字符串,匹配关联表或别名
scope.joins!("INNER JOIN assocs AS my_assoc ON my_model.id = my_assoc.my_model_id") scope.joins_values.any? { |v| v.is_a?(String) && v.include?("assocs AS my_assoc") }
获取关联的别名
同样需要通过解析查询对象的内部结构来提取别名:
- 命名关联的自动别名:借助
arel的join_sources获取自动生成的别名
scope = MyModel.joins!(assoc: :nested) reflection = MyModel.reflect_on_association(:assoc) # 遍历join源匹配关联表,提取别名 scope.arel.join_sources.each do |join| if join.left.name == reflection.table_name puts join.left.table_alias # 输出关联的别名 end end
- 自定义SQL中的手动别名:直接从
joins_values的SQL字符串中匹配提取
scope.joins!("INNER JOIN assocs AS my_assoc ON ...") alias_match = scope.joins_values.grep(String).first.match(/AS (\w+)/) alias_name = alias_match ? alias_match[1] : nil
封装复用工具
可以将逻辑封装成查询对象的扩展方法,方便全局使用:
module JoinTrackingHelpers # 检查指定关联是否已被join def joined_association?(name) joins_values.any? do |val| case val when Symbol, String then val == name when Hash then val.key?(name) end end end # 获取指定关联的别名(无别名则返回表名) def association_alias(name) reflection = self.class.reflect_on_association(name) return nil unless reflection arel.join_sources.each do |join| if join.left.name == reflection.table_name return join.left.table_alias || reflection.table_name end end nil end end ActiveRecord::Relation.include(JoinTrackingHelpers)
使用示例:
scope.joined_association?(:assoc) # 返回true/false scope.association_alias(:assoc) # 返回别名或表名
内容的提问来源于stack exchange,提问作者Ryan Pierce Williams
相关产品推荐
相关产品推荐

