Rails中如何用ActsAsTaggableOn获取用户帖子的最常用标签
Rails中查询指定用户帖子的最常用标签(ActsAsTaggableOn实现)
错误原因
你之前写的ActsAsTaggableOn::Tag.most_used.joins(:posts).where(user_id: current_user.id)报错,核心原因是ActsAsTaggableOn的Tag模型默认没有和Post建立直接关联,gem本身是通过内置的taggings多态中间表关联所有打了标签的业务模型,不能直接join posts表。
正确实现方法
你可以选以下两种方案,都不需要额外修改模型关联:
方案1:通过中间表直接关联查询(性能最优,推荐)
直接利用gem自带的taggings中间表做关联过滤,逻辑和gem原生most_used完全一致,只是增加了用户帖子的过滤条件:
# 构造当前用户所有帖子的ID查询关系(不会立刻加载全量数据,作为子查询性能更好) user_posts = current_user.posts # 关联中间表过滤当前用户的帖子标签,按使用频次倒序 ActsAsTaggableOn::Tag .joins(:taggings) .where( taggings: { taggable_type: Post.name, # 固定匹配Post模型,避免多态关联查错其他模型的标签 taggable_id: user_posts.select(:id) } ) .group("tags.id") .order(Arel.sql("COUNT(taggings.id) DESC")) # 要取Top N标签就加limit,比如.limit(10)取前10个最常用标签
这个写法全程走SQL查询,没有Ruby层的遍历开销,数据量大的时候性能表现最好。
方案2:利用Post模型的标签计数方法(写法最简)
只要你的Post模型已经正确声明了acts_as_taggable_on :tags,就可以直接用gem提供的tag_counts_on方法拿到当前用户所有帖子下按使用频次排序的标签集合:
# 返回结果已经按标签使用次数从高到低排序,每个标签对象自带taggings_count字段存使用次数 user_top_tags = current_user.posts.tag_counts_on(:tags)
如果你需要复用Tag模型上的其他scope,也可以写成过滤ID的形式:
ActsAsTaggableOn::Tag .where(id: current_user.posts.tag_counts_on(:tags).map(&:id)) .most_used
这个写法代码量少,适合数据量不大的场景,缺点是会多一次查询,存在Ruby层的ID映射开销。
前置检查
确保你的Post模型配置正确,否则上述方法会失效:
# app/models/post.rb class Post < ApplicationRecord belongs_to :user # 必须声明标签能力,上下文名如果自定义过,把:tags换成你自己的命名 acts_as_taggable_on :tags end
内容的提问来源于stack exchange,提问作者GabrielTheCoder
相关产品推荐
相关产品推荐

