Rails 5 ActiveRecord Sanitized Order By

It may surprise you to find out that the default rails order function does not sanitize input. This can lead to potentially dangerous sql injections. Additionally, Rails 5 is starting to throw warnings when using order or sanitize_sql_for_order:

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "field(id, ?)". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql().

I don’t like users to be able to cause sql errors even with the worst input. I like clean logs. I went looking for someone who has solved this problem but didn’t find much. There was a decent sanitation function in a gist on github but it doesn’t work with joins. Here is a version of that function that operates cleanly when used on a joined query.

# Refactored from https://gist.github.com/TheKidCoder/9653073
class ActiveRecord::Relation
  def sanitized_order(order_by, direction = 'ASC')
    if order_by.include?('.')
      klass, column = order_by.split('.')
      unless joins_values.include?(klass.pluralize.to_sym)
        raise "#{klass} unavailable in query"
      klass = klass.singularize.classify.constantize
      klass = self.klass
      column = order_by

    raise "Column #{column} not found in #{klass.name}" unless klass.column_names.include?(column.to_s)
    raise 'Invalid direction value' unless %w[ASC DESC].include?(direction.upcase)

    order("#{order_by} #{direction.upcase}")

Thank you

Your comment has been submitted and will be published once it has been approved.


Your comment has not been submitted. Please go back and try again. Thank You!

If this error persists, please open an issue by clicking here.

Say something