【问题标题】:Convert Ruby expression to Arel将 Ruby 表达式转换为 Arel
【发布时间】:2013-09-23 21:55:23
【问题描述】:
我有一个表达式,根据当前用户给他们的星数来挑选前三名评论
@event.reviews.sort_by { |r| -r.stars.select{ |s| s.user_id == current_user.id }.count }.first(3)
问题在于,它将所有评论和星标拉入内存,并在 Ruby 中执行此操作。除了在直接 SQL 中执行此操作外,有没有办法在 arel 中实现相同的操作,以便数据库完成大部分计算而不是 Ruby?
【问题讨论】:
标签:
ruby
activerecord
arel
【解决方案1】:
你可以使用以下,counter这里代表stars的数量从current_user为review
# Single query with inner join
@event.reviews.joins(:stars)
.select("reviews.*, stars.id ,SUM(stars.user_id = #{current_user.id}) AS counter ")
.group("reviews.id ")
.order("counter DESC").limit(3)
上面的sql查询会创建一个reviews和stars的内连接表。
根据这些表的大小,在获取@event 时,为事件预加载reviews 和stars 可能会更快。例如
# Eager loading with separate queries
@event = Event.find(params[:id]).includes(:reviews => :stars)
上述方法将进行一次查询以获取与该事件相关的所有评论的所有星星。
如果你在同一个请求的其他地方使用了stars和reviews,那么最好用includes预先加载它们。