繁体   English   中英

在Rails 4中将find_by_sql语法转换为正确的Active Record AREL语法

[英]Converting find_by_sql syntax to proper Active Record AREL syntax in Rails 4

给定一个具有三维坐标x,y和z的系统模型,我编写了以下实例方法,以为我提供所讨论特定系统的设定范围内的所有其他系统。 这是代码:

def systems_within(range = '15')
  System.find_by_sql(["SELECT * FROM systems WHERE Sqrt(Pow((:x - systems.x), 2) + Pow((:y - systems.y), 2) + Pow((:z - systems.z), 2)) <= :range AND id!= :current_id", {x: x, y: y, z: z, range: range, current_id: id}])
end

是否有ActiveRecord的方法?

由于您需要访问当前实例,因此需要保留实例方法,但是您可以通过将部件移到作用域中来对其进行分解(我想这就是ActiveRecord的意思)。

这样的事情可能会起作用。 这是未经测试的代码。

scope :within_range, -> (x, y, z, range = '15') {
  where("Sqrt(Pow((:x - systems.x), 2) + Pow((:y - systems.y), 2) + Pow((:z - systems.z), 2)) <= :range", {x: x, y: y, z: z, range: range})
}
scope :excluding, -> (excluded_id) { where("id <> ?", excluded_id) }

def systems_within(range = 15)
  System.excluding(id).within_range(x, y, z, range)
end

通过与范围的平方进行比较,可以使数据库进行较少的计算:

square_range = range**2

“从系统中选择*”是隐式的,因此您只需要调用where子句。 我将这些条件留给SQL片段进行复杂的计算:

System.where(
   'Pow((:x - x), 2) + Pow((:y - y), 2) + Pow((:z - z), 2)) <= :square_range', 
    {x: x, y: y, z: z, square_range: square_range}
).where.not(id: current_id)

请注意,此处仅使用x而不是systems.x ,因为另一个:x只是参数,而不是自己的数据库对象。

像Brad Pauly所建议的那样,将所有范围都放在这也是一个好主意。 顺便说一句,调用您的类“ System”可能很危险,因为ruby有一个进行操作系统调用的system方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM