Rails/Arel如何查询带总发帖数、删帖数的完整User模型列表
实现方案
前提准备
首先确认User模型中已经配置了和Post的反向关联,外键要和Post侧的定义对应:
# app/models/user.rb class User < ApplicationRecord has_many :posts, foreign_key: :uploader_id end
方案1:从User模型发起查询(推荐)
你需要返回的主体是User实例,从User侧查询逻辑更直观,不会出现类型匹配问题:
users = User.arel_table posts = Post.arel_table user_list = User # 若不需要展示从未发帖的用户,可将left_joins改为joins .left_joins(:posts) .select( users[Arel.star], # 选中User表所有字段,保证返回完整User实例 posts[Arel.star].count.as("total_posts"), # 统计总发帖数 Arel::Nodes::Sum.new( Arel::Nodes::Case.new.when(posts[:is_deleted].eq(true)).then(1).else(0) ).as("deleted_posts_count") # 统计已删除帖子数 ) .group(users[:id]) # 按User主键分组,符合SQL规范 .order(total_posts: :desc, deleted_posts_count: :desc) .limit(20)
查询结果中的每个元素都是完整的User实例,除了可以调用User模型的所有原有方法外,还可以直接读取额外统计字段:
user_list.each do |user| puts "用户名:#{user.name},总发帖:#{user.total_posts},已删除:#{user.deleted_posts_count}" end
方案2:简化原生SQL片段写法
如果觉得Arel语法太复杂,也可以直接用安全的固定SQL片段实现,对新手更友好:
user_list = User .left_joins(:posts) .select( "users.*", "COUNT(posts.id) as total_posts", "SUM(CASE WHEN posts.is_deleted = TRUE THEN 1 ELSE 0 END) as deleted_posts_count" ) .group("users.id") .order("total_posts DESC") .limit(20)
原代码报错原因
你从Post模型发起查询,默认返回的是Post实例而非User实例,仅join关联不会自动返回关联表的完整对象,select中仅写:uploader也只会返回uploader_id字段,所以无法拿到完整的User数据。
内容的提问来源于stack exchange,提问作者Some Guy
相关产品推荐
相关产品推荐

