Frage

am reading data from a user-supplied CSV file of unknown number of rows. I iterate through the rows and rather than individually insert each row individually into the database (potentially a performance hurting large number of inserts), I concatenate the values into a single string:

insert_values += ", (#{params[:quantity]}, #{'#{params[:name]}', '#{Time.now.to_s(:db)}')"

I then build the full sql query:

sql = "INSERT INTO `my_table` (`quantity`, `name`, `created_at`) VALUES"+insert_values

Finally, I execute it:

ActiveRecord::Base.connection.execute(sql)

I want to make the data safe from malicious injection. What is the best way to do this?

War es hilfreich?

Lösung 3

Thanks for all the helpful advice which led me down my final path. I ended up changing my string to an array of values to take advantage of Rails built-in method, sanitize_sql_array after reading another post.

placeholders = []
insert_values = []

csvrow.each do |row|
  placeholders << (?,?,?)
  insert_values << params[:quantity] << #{params[:name]} << {Time.now.to_s(:db)
end

query_string = "INSERT INTO `my_table` (`quantity`, `name`, `created_at`) VALUES #{placeholders.join(", ")}"] + insert_values
sql = ActiveRecord::Base.send(:sanitize_sql_array, query_string)
ActiveRecord::Base.connection.execute(sql)

Andere Tipps

If you're going to do this then you need to take the time to escape every field going into the db using AR's underlying connection escape methods. Otherwise you are just asking for trouble.

Or... use something else that is meant for doing a lot of volume, but still handles the escaping for you... https://github.com/zdennis/activerecord-import

You could consider using MySQL LOAD DATA INFILE syntax to insert your CSV data. It is optimized for upload and doesn't require you to manually build an injection-prone query string.

Here is link to MySQL docs:

http://dev.mysql.com/doc/refman/5.6/en/load-data.html

LOAD DATA [LOCAL] INFILE '/path/to/data.csv'
INTO table
FIELDS TERMINATED BY ',' ENCLOSED BY '' ESCAPED BY '\'
LINES TERMINATED BY '\n'

Note use LOCAL if app server and database are on different machines. you might need to change field and line settings based on the format of your CSV.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top