Thanks for your help with this one! I'm working on a legacy Rails application and I've checked a few sources but haven't been able to make them work for my situation. In Rails 2.3, I've got a search form (index.html.erb) and a controller (search.rb). The controller uses the search fields to build a string, which is saved in the variable @search_string.
@search_string = ""
To show the results of the search, the controller uses:
@location_matches = Location.paginate_by_sql("select * from locations where #{@search_string} order by nickname asc", :page => params[:page], :per_page => 20)
What is the simplest way for me to sanitize the above? I tried
@location_matches = Location.paginate_by_sql('SELECT * FROM locations WHERE #{@search_string} = ?', @search_string)
This throws the error ArgumentError (parameter hash expected). FYI, the @search_string is built with form fields like this:
FORM
<label for="city">City</label>
<input id="city" name="city" size="30" type="text" value="" />
CONTROLLER
if params[:city] != ""
@search_string << "and city like '%#{params[:city]}%' "
if @first_term == 'y'
@search_string = @search_string.gsub('and ', " ")
@first_term = 'n'
end
end
I'm pretty sure the individual fields aren't properly parameterized, but rather than go through every field and try and fix it, I was looking for a faster solution by just tweaking the paginate_by_sql statement (I'm new to Rails and am just trying to make a quick fix since the whole app will eventually need upgrading.)
EDIT
I followed the steps in Rails, how to sanitize SQL in find_by_sql and added an initializer. I also changed my statement to the below. However, when I run my search, I get no results. I also had to delete the ascending condition because it threw an error. Any ideas are very welcome!
Initializer
class ActiveRecord::Base
def self.escape_sql(clause, *rest)
self.send(:sanitize_sql_array, rest.empty? ? clause : ([clause] + rest))
end
end
Controller
query = Location.escape_sql(["SELECT * from locations WHERE #{@search_string} = ?", params[:@search_string]])
@location_matches = Location.paginate_by_sql(query, :page => params[:page], :per_page => 20)
Log (Looks the same as the code that returns results)
Parameters: {"city"=>"New York", "commit"=>"Search", "search"=>{"size_category"=>"", "state"=>""}}