Skip to content

Instantly share code, notes, and snippets.

@TheKidCoder
Last active October 29, 2020 18:40
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save TheKidCoder/9653073 to your computer and use it in GitHub Desktop.
Save TheKidCoder/9653073 to your computer and use it in GitHub Desktop.
Rails - Sanitize Ordering Params
class ExampleController
include OrderingHelpers
def index
@clients = Clients.order(sanitized_ordering).where(user_id: current_user.id)
end
end
module OrderingHelpers
extend ActiveSupport::Concern
def sanitized_ordering
"#{sanitize_column(params[:order_by])} #{sanitize_column_direction(params[:sort_direction])}"
end
private
def sanitize_column(column)
resource.column_names.include?(column) ? column : "created_at"
end
def sanitize_column_direction(direction)
direction = direction.upcase
['DESC', 'ASC'].include?(direction) ? direction : "DESC"
end
def resource
controller_name.camelize.singularize.safe_constantize
end
end
@dmexs
Copy link

dmexs commented Oct 4, 2015

This pattern doesn't seem to work for joined queries. sanitize_column verifies column names that exist only for the current controller.

I forked it and made it switchable: https://gist.github.com/dmexs/ebcfe76d9c282bb205ee

@joshuapinter
Copy link

FYI, I ended up extending ActiveRecord::Relation in order to create a sanitized_order() method that accepts the column and direction to sort on. It can be improved to work with other class column names, etc. but it does the job for now:

config/initializers/sanitized_order.rb

class ActiveRecord::Relation

  # This will sanitize the column and direction of the order. Should always be used when taking these params from GET.
  #
  def sanitized_order( column, direction = nil )
    direction ||= "ASC"

    raise "Column value of #{column} not permitted."       unless self.klass.column_names.include?( column.to_s ) 
    raise "Direction value of #{direction} not permitted." unless [ "ASC", "DESC" ].include?( direction.upcase ) 

    self.order( "#{column} #{direction}" )
  end

end

And then you simply call it in the query chain like:

Client.sanitized_order( params[:order_by], params[:sort_direction] ).where(user_id: current_user.id)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment