3

I am trying to allow the end-user of a rails app to limit results based on the value of an arbitrary column. At its simplest, I want to do something roughly equivalent to:

"SELECT * FROM products WHERE (#{params[:min_col]} >= #{params[:min]})"

without the injection vulnerability.

For example, example.com/myapp/catalog?min_col=sell_price&min=300 would return all products with sell_price greater than or equal to $3.00

I tried adding a scope like this to the model:

->(column,min) { where("? >= ?", column, min) }

and passing the uri parameters to that scope, but this yields

WHERE ('sell_price' >= '300')

which seems to just be comparing two literal strings -- this query and others like it always return every row or no rows. How do I get the desired behavior of comparing against a column specified in params?

3
  • Rails v. 3.2.16 Ruby 1.9.3 Commented Jun 11, 2014 at 17:41
  • I think ransack will help you here. Read the docs and give it a try. github.com/activerecord-hackery/ransack Commented Jun 11, 2014 at 17:47
  • @user3678068's solution is about the best you will do. The validation of the column taken from parameters is essential to prevent SQL injection attacks. The ? escape will always convert the Ruby type into the corresponding SQL type. Ergo the quotes for strings. I thought a symbol might work but tried and found it does not. You get the quotes for the symbol as well. Commented Jun 11, 2014 at 19:13

1 Answer 1

5

To prevent sql injection, you should validate the column is a valid one

valid_cols = ["c1", "c2"]
valid_cols.include?(column) or raise "Bad query"

Then you can just use the query interface as before

Model.where("#{column} >= ?", min)
Sign up to request clarification or add additional context in comments.

2 Comments

You can #column_names to determine if the column is valid, ie. Model.column_names.include? params[:min_col] instead of duplicating the column list as shown above.
good advice, but sometimes you may not want to expose all fields

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.