如何按Activerecord中的计算值排序?

时间:2017-10-16 21:42:41

标签: ruby-on-rails activerecord rails-activerecord

我有一个rails API,它将JSON返回到我的React前端。我正在尝试按集合中每个项目的计算值进行排序。我有Space模型,其中包含area属性和count属性。我想按total_areaarea * count进行排序。我可以使用sort_by执行此操作,但即使记录少于100个,此过程也非常缓慢:

@spaces = Space.all
@spaces = @spaces.sort_by(&:total_area) 

其中total_areaSpace类方法:

def total_area
  self.area * self.count
end

有没有在数据库中这样做才能提高速度?我尝试使用order方法:

@spaces.order( "count * area" => :asc)

但我得到以下postgres错误:

PG::UndefinedColumn: ERROR:  column spaces.count * area does not exist

可以在数据库中执行此操作吗?任何有关我如何能够提出的建议,或者我如何更快地做到这一点都将非常感激。

1 个答案:

答案 0 :(得分:5)

当您递送#order哈希时:

@spaces.order("count * area" => :asc)

它假定密钥是列名,因此它将这样的SQL发送到数据库:

order by "count * area" asc

因此PG::UndefinedColumn例外。顺便说一句,在SQL中使用双引号来引用列和表名等标识符。

如果要将表达式作为ORDER BY子句的一部分发送到数据库,那么您希望将该表达式作为字符串传递给#order

@spaces.order('count * area')
# If you want to be explicit about the sorting direction:
@spaces.order('count * area asc')
# If you might have other tables with those column names:
@spaces.order('spaces.count * spaces.area')

请注意,较新版本的Rails会抱怨:

  

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s)

当您尝试将字符串传递给#order时,您可以通过添加Arel.sql电话来解决这个问题:

@spaces.order(Arel.sql('count * area'))
@spaces.order(Arel.sql('count * area asc'))
@spaces.order(Arel.sql('spaces.count * spaces.area'))