0

给定一个具有三维坐标x,y和z的系统模型,我写了下面的实例方法给我所有其他系统在一个设置范围内具体系统的问题。这里的代码:将find_by_sql语法转换为Rails 4中正确的Active Record AREL语法

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这样做?

回答

2

因为你需要访问当前实例,所以你需要保留实例方法,但是你可以通过将部分移动到范围中来分解它(我猜这就是你的意思是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 
+0

谢谢。这工作。我将它与上面的其他答案结合起来。 – GreenPlastik

1

可以让数据库通过对 平方的范围内的比较少做算了一笔账:

square_range = range**2 

的“从系统中选择*”是隐含的,所以你只需要调用哪里条款。我会留下这样的条件复杂的计算,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所说的那样,也是一个好主意。 顺便说一句,调用你的类“系统”可能是危险的,因为ruby有一个system方法来进行操作系统调用。

+0

感谢您的回复。我把这个与Brad的回答结合起来,放在范围内。在其他情况下使它更容易使用 – GreenPlastik

相关问题