本当にこのアプローチが正しいか検討しながら書いているのであしからず。
sanitize_sql_for_orderを使えばいいんじゃ?という説もあり
# Contorollerなどで
# SQLインジェクションできる実装
User.where(name: "Name").order(params[:f]=>params[:o])
# SQLインジェクション対策された実装
User.where(name: "Name").safe_order(params[:f], params[:o])
safe_orderメソッドは下記のように実装しています。
module SafeOrder
extend ActiveSupport::Concern
included do
scope :safe_reorder, -> (key_string, order_string, **args) {
if string = self.safe_order_string(key_string, order_string, **args)
reorder(string)
end
}
scope :safe_order, -> (key_string, order_string, **args) {
if string = self.safe_order_string(key_string, order_string, **args)
order(string)
end
}
end
class_methods do
def safe_order_string(key_string, order_string, **args)
args = {safe_keys: []}.merge args
safe_keys = self.column_names.push(args[:safe_keys].map(&:to_s)).flatten.uniq
_key = ([key_string.to_s.downcase] & safe_keys).first
_order = ([order_string.to_s.downcase] & ["asc", "desc"]).first
if _key.present? && _order.present?
"#{_key} #{_order}"
else
raise "order by unknown keys" if Rails.env.development? || Rails.env.test?
nil
end
end
end
end