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

时间:2015-10-09 17:04:21

标签: ruby-on-rails ruby-on-rails-4 activerecord rails-activerecord find-by-sql

给定具有三维坐标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这样做?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

您可以通过与数据库进行比较来让数据库执行更少的计算 范围广场:

new

&#34;选择*来自系统&#34;是隐式的,所以你只需要调用where子句。我将这些条件与SQL片段进行复杂的计算:

square_range = range**2

请注意,这里只使用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只是参数,而不是自己的数据库对象。

把这些全部放在范围内,就像Brad Pauly建议的那样,也是一个好主意。 顺便说一下,打电话给你的班级&#34;系统&#34;可能很危险,因为ruby有一个:x方法来进行操作系统调用。