Sanitizing SQL in Rails where conditions may be NULL

前提是你 提交于 2020-01-03 04:30:06

问题


I'm struggling to sanitize a raw SQL query in which the WHERE conditions may either have a value or be NULL. I was hoping to use Active Record's built-in sanitizers...

(NOTE: I'll be using a simplified query for demo purposes- our real one is a complex UNION across different model types that would be hard to do with the AR query interface)

Try 1:

raw_query = "SELECT * FROM folders WHERE user_id = ? AND parent_id = ?"
sanitized_query = ActiveRecord::Base.send(:sanitize_sql_array, [raw_query, current_user.id, params[:parent_id]])
results = ActiveRecord::Base.connection.execute(sanitized_query);

But if params[:parent_id] is nil, then sanitized_query ends up as SELECT * FROM folders WHERE user_id = 1 AND parent_id = NULL Which isn't valid, as parent_id = NULL should be parent_id IS NULL

Try 2:

I then found the sanitize_sql_hash method, which seemed perfect for building the condition:

sanitized_conditions = ActiveRecord::Base.send(:sanitize_sql_hash, {user_id: current_user.id, parent_id: params[:parent_id]})
sanitized_query = "SELECT * FROM folders WHERE #{sanitized_conditions}"
results = ActiveRecord::Base.connection.execute(sanitized_query);

But the first line fails with:

NoMethodError: undefined method `abstract_class?' for Object:Class

The method is also listed as deprecated and will be removed in Rails 5, but it's exactly what I'm looking for. Is there another way to generate a safe WHERE condition from a hash of values?


回答1:


It looks like the error is being thrown in the reset_table_name method at https://github.com/rails/rails/blob/7bb620869725ad6de603f6a5393ee17df13aa96c/activerecord/lib/active_record/model_schema.rb#L160 so maybe this method is not designed to work on the ActiveRecord::Base class.

Assuming you have got a model class for Folder this should work:

Folder.send(:sanitize_sql_hash, {user_id: current_user.id, parent_id: params[:parent_id]})

In a quick test I got something like:

'"folders"."user_id" = 123 AND "folders"."parent_id" IS NULL'



回答2:


I created a Rails 5-safe version of the deprecated but much needed sanitize_sql_hash_for_conditions, using @Steve's trick:

class ActiveRecord::Base 

  # Sanitizes a hash of attribute/value pairs into SQL conditions for a WHERE clause.
  #
  # (This is an alternative to sanitize_sql_hash_for_conditions, which was deprecated in Rails 5.
  # SEE: https://api.rubyonrails.org/v4.2/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_hash_for_conditions)
  # 
  # This is needed because the latest SQL sanitization methods cannot handle conditions where an attribute is nil.

  def self.sanitize_sql_hash_for_conditions_alt(attrs)
    self.where(attrs).to_sql.split('WHERE ')[1]
  end

end

Call it on whatever AR model class represents the table you're targeting (not on ActiveRecord::Base directly).

Folder.sanitize_sql_hash_for_conditions_alt({user_id: 1, parent_id: nil})
=> "\"folders\".\"user_id\" = 1 AND \"folders\".\"parent_id\" IS NULL"



来源:https://stackoverflow.com/questions/28001762/sanitizing-sql-in-rails-where-conditions-may-be-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!