2012-06-01 3 views
1

Как это сделать, не рискуя атакой SQL-инъекций?Как безопасно вставить параметры в ActiveRecord минимум

nearest = Site.minimum('abs(latitude - ' + params[:lat] + ') - abs(longitude - ' + params[:lon] + ')', group: :id) 

Я пробовал:

nearest = Site.minimum(['abs(latitude - ?) - abs(longitude - ?)', params[:lat], params[:lon]], group: :id) 

Но это не похоже на работу. Документация не очень ясна, как это сделать.

Заранее благодарен!

+0

Согласно [этому Rails API] (http://api.rubyonrails.org/classes/ActiveRecord/Base.html) второй способ, которым вы написали *, - это безопасный путь. Что с этим не получилось? – MrDanA

+0

Второй способ не работает, поскольку он ожидает имена столбцов, когда видит массив. Этот синтаксис работает только тогда, когда() и: conditions => –

+0

При использовании функций sql строители рельсов начинают разрушаться. Возможно, вам стоит взглянуть на Squeel, который лучше поддерживает функции sql: https://github.com/ernie/squeel (или railscast: http://railscasts.com/episodes/354-squeel) – DGM

ответ

1

Rails использует sanitize_sql_for_conditions для работы с заполнителями. Конечно, этот метод защищен, поэтому вы не можете (чисто) использовать его вне модели ActiveRecord. Вы можете обойти с помощью send защищенности:

nearest = Site.minimum(
    Site.send(:sanitize_sql_for_conditions, [ 
     'abs(latitude - ?) - abs(longitude - ?)', 
     params[:lat].to_f, params[:lon].to_f 
    ] 
) 

Или вы могли бы поместить эту логику внутри метода Site класса, так что вы бы разрешили использовать sanitize_sql_for_conditions без обмана:

class Site < ActiveRecord::Base 
    def self.whatever_this_is(lat, lon) 
     minimum(
      sanitize_sql([ 
       'abs(latitude - ?) - abs(longitude - ?)', 
       lat, lon 
      ]) 
     ) 
    end 
end 

, а затем в ваш контроллер:

nearest = Site.whatever_this_is(params[:lat].to_f, params[:lon].to_f) 

Обратите внимание на звонки to_f. Если вы не включают в себя то params[:lat] и params[:lon] будет Струны и sanitize_sql_for_conditions процитирую их как таковые:

abs(latitude - '11.23') - abs(longitude - '42.6') 

Ваша база данных может или не может быть счастлив видеть, что вы пытаетесь вычесть строку из числа так оно лучше всего сказать, что вы имеете в виду и сделать преобразование типа самостоятельно.

+0

Спасибо. Я решил для этого: c = ActiveRecord :: Base.connection; ближайший = Site.select ('ABS (широта -' + c.quote (params [: lat]) + ') - abs (longitude -' + c.quote (params [: lon]) + ') AS distance, id «) .order (: расстояние) .limit (1) –

0

Предоставлено. Я не могу сказать, что вы пытаетесь выполнить из приведенного выше примера, но похоже, что вы можете неправильно использовать минимальный метод, который принимает имя метода в качестве его первого аргумента. Например:

Site.minimum(:latitude) 

Если вы хотите добавить условия к этому, я думаю, что вы хотели бы использовать:

Site.where(country: 'USA').group(:id).minimum(:latitude) 

Опять же, этот пример не будет возвращать результат вы ожидаете, но он должен лучше объяснить, как используется API.

Смежные вопросы