簡體   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