0

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

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 方式吗?

4

2 回答 2

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
于 2015-10-09T21:41:04.327 回答
1

您可以通过与范围的平方进行比较来让数据库做更少的计算:

square_range = range**2

“select * from systems”是隐含的,所以你只需要调用 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 建议的那样,将所有内容放在范围内也是一个好主意。顺便说一句,调用你的类“系统”可能很危险,因为 ruby​​ 有一种system方法来进行操作系统调用。

于 2015-10-09T22:17:02.103 回答