Rails中合并不同范围ActiveRecord::Relation实现未处理举报数准确统计
实现方案
同模型scope合并(仅合并UserReports相关scope)
如果不需要包含UserBlockLog的举报数据,直接用or方法链式合并所有scope即可,全程返回ActiveRecord::Relation:
# 定义要合并的scope列表 user_report_scopes = [ UserReports.unprocessed.videos, UserReports.unprocessed.public_chats, UserReports.unprocessed.answers_only, UserReports.unprocessed.questions_only.questions_reasons, UserReports.unprocessed.profiles.profiles_reasons ] # 合并为单个Relation merged_reports = user_report_scopes.inject(UserReports.none) do |merged, scope| merged.or(scope) end
merged_reports就是合并后的Relation对象,后续可直接链式调用其他scope、count、分页等操作。
跨模型scope合并(包含UserBlockLog数据)
如果需要合并UserReports和UserBlockLog两个模型的数据,需要保证两个查询的字段数量、类型完全对齐,用UNION构造Relation:
# 先合并UserReports的所有scope,查询字段和UserBlockLog对齐 user_report_rel = user_report_scopes.inject(UserReports.none) do |r, s| r.or(s) end.select(:id, :origin, :reason, :state, " 'UserReports' as source_type") # 构造UserBlockLog的查询,字段和上述对齐(字段名不同的话用别名统一) block_log_rel = UserBlockLog.unprocessed.photos.select(:id, :origin, :reason, :state, " 'UserBlockLog' as source_type") # 用arel构造UNION查询,返回Relation union = Arel::Nodes::Union.new(user_report_rel.arel, block_log_rel.arel) merged_relation = ActiveRecord::Base.from(union.as('combined_reports'))
原方法适配调整
你原来的other_total_reports可以调整为支持多scope合并的版本:
def other_total_reports(subjects_list, action, due_in = nil, locale_clause = nil) # 合并传入的所有scope merged_subjects = subjects_list.inject(subjects_list.first.model.none) do |merged, scope| merged.or(scope) end scopes = [] scopes << due_in if due_in count = scopes.inject(merged_subjects) { |obj, method| obj.public_send(method) }.count link_to count, { controller: 'user_reports', action: action, filter: filter }, class: ("overdue" if due_in == :overdue), target: "_blank" end
调用方式:
all_subjects = [ UserReports.unprocessed.videos, UserReports.unprocessed.public_chats, UserReports.unprocessed.answers_only, UserBlockLog.unprocessed.photos, UserReports.unprocessed.questions_only.questions_reasons, UserReports.unprocessed.profiles.profiles_reasons ] other_total_reports(all_subjects, 'index')
注意事项
- 用
or合并的多个Relation必须保证where、select、group等结构兼容,否则会抛出语法错误 - 跨模型合并时必须严格对齐查询字段的数量、类型,字段名不同的话用
as设置统一别名 - 整个合并过程没有触发查询转数组,完全满足后续对Relation的操作需求
内容的提问来源于stack exchange,提问作者Константин Гришунин
相关产品推荐
相关产品推荐

