views:

55

answers:

3

I'm trying to pass in both the field and the value in a find call:

@employee = Employee.find(:all,
              :conditions => [ '? = ?', params[:key], params[:value].to_i)

The output is

SELECT * FROM `employees` WHERE ('is_manager' = 1)

Which returns no results, however when I try this directly in mysqsl using the same call without the '' around is_manager, it works fine. How do I convert my params[:key] value to a symbol so that the resulting SQL call looks like:

SELECT * FROM `employees` WHERE (is_manager = 1)

Thanks, D

+3  A: 

If you want to convert a string to symbol(which is what params[:key] produces, all you need to do is

params[:key].to_s.to_sym

2 points:

  1. A word of caution : symbols are not garbage collected.

  2. Make sure your key is not a number, if you convert to_s first then to_sym, your code will work but you may get a wierd symbol like this:

    :"5"

Nick Gorbikoff
Thanks Nick. I'm afraid I asked the wrong question perhaps. @employee = Employee.find(:all, :conditions => [ '? = ?', params[:key].to_s.to_sym, params[:value].to_i)Produces the following SQL output:SELECT * FROM `employees` WHERE ('--- :is_manager\n' = 1)I think I must have a error in my logic rather than syntax. I could do a case statement where I check what the params[:key] is and do the appropriate find (in this case it would be [:is_manager = ?, params[:value].to_i]). But I was hoping to be a bit more dynamic and not have to redo each case individually.
DarrenD
I kind of answered what you asked, not what you meant :-) I'm not sure what you ask for is possible or most importantly - desired, at least not according to rails spec http://api.rubyonrails.org/classes/ActiveRecord/Base.html . The problem is that it's a potential big security hole. Assume this is an HR application: what if somebody will pass for a key = salary. Then they can potentially pull salary info or ssn info for any person. I mean sure you could put all sort of role-based security, but that would defeat the purpose of saving you time you would spent writing out your case statement.
Nick Gorbikoff
Gotcha. The key is coming from a select box, so I'm only accepting specific values (plus I'm authenticating as this is an 'admin' tool). But I hear ya. Case statement it is :)
DarrenD
+1  A: 

"string".to_sym

kingjeffrey
+1  A: 

You could use variable substitution for column name instead of using bind values:

# make sure the key passed is a valid column
if Employee.columns_hash[params[:key]]
  Employee.all :conditions => [ "#{params[:key]} = ?", params[:value]]
end

You can further secure the solution by ensuring column name passed belongs to a pre selected set.:

if ["first_name", "last_name"].include? [params[:key]]
  Employee.all :conditions => [ "#{params[:key]} = ?", params[:value]]
end
KandadaBoggu
Fixed the syntax error in the code.
KandadaBoggu
I still think it's a bad idea from a security standpoint.
Nick Gorbikoff
This is a generic solution. User can have a valid keys hash and use that for validation (instead of columns_hash). His original issue is due to the fact the col name was substituted using the bind variables and rails surrounded the col names with quotes. This will not be addressed by passing a symbol (instead of string) for col name parameter. I added `columns_hash` validation as a guide line for adding a check to limit the column names to a known set. That should the security issue.
KandadaBoggu