2011-01-14 11 views
28

私はプリペアドステートメントについて知っていますが、生のSQLを使用している場合、ActiveRecordは手動で値をエスケープする方法がありますか?このようなRailsの値をエスケープする(mysql_real_escape_string()と似ています)

何かがいいだろう:あなたはまだ疑問符をエスケープ値として立つフォームを使用することができます

self.escape("O'Malley") # O\'Malley 

答えて

53

を:

Dude.sanitize("O'Malley") 

または

Dude.connection.quote("O'Malley") 

両方とも同じ結果と:誰かに@ jemmingerのソリューションのより具体的な例を探している場合は=> "'O''Malley'"

+3

私はあなたのモデルネームが大好きです。 「おい、あなたは素晴らしいよ。 –

+6

@NateSymer:そうです、それはあなたの意見のようです。 – Fuser97381

+2

誰かが疑問を持っている場合は、はい、それらはまったく同じです:[sanitize calls connection.quote](http://apidock.com/rails/ActiveRecord/Base/sanitize/class) – mltsy

4

でもModel.find_by_sqlで。

は、単に最初の要素が照会され、後続の要素がで置換される値である配列を渡しRailsのAPIドキュメントから

例:

Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
+0

を返し

Dude.connection.quote_string("O'Malley") 

を挿入するとどうなりますか? –

+1

私はそれを掘り下げることができますが、実際にはなぜActiveRelation/ActiveModelの外に挿入していますか? –

+1

私は 'INSERT IGNORE'をやっていて、パフォーマンスのために一つのステートメントで複数のレコードを更新しています。 –

19

を簡単にmysql2を使用することができ宝石は、これを実行します

irb(main):002:0> require 'rubygems' 
=> true 
irb(main):003:0> require 'mysql2' 
=> true 
irb(main):004:0> Mysql2::Client.escape("O'Malley") # => "O\\'Malley" 
=> "O\\'Malley" 

場合や、以前のMySQLを使用して(ないmysql2)宝石:

irb(main):002:0> require 'rubygems' 
=> true 
irb(main):003:0> require 'mysql' 
=> true 
irb(main):004:0> Mysql.escape_string("O'Malley") 
=> "O\\'Malley" 

これにより、必要なものをエスケープしてデータベースに挿入できます。また、あなたのレールアプリケーションのほとんどのモデルで、sanitizeメソッドを使ってこれを行うことができます。たとえば、Personというモデルがあるとします。あなたはすることができます。

Person.sanitize("O'Malley") 

これはすべきことです。

+0

奇妙な...これは促進された答えだった...そして変更された... arg。 – quest

+10

Mysql2 gemで: 'Mysql2 :: Client.escape(" O'Malley ")#=>" O \\ 'Malley "' – Duke

31

迅速なダイビングActiveRecordのソースは、SQL文の[string, bind_variable[, bind_variable]]タイプ

を消毒するために、その方法 "sanitize_sql_array" を明らかにあなたはそれを直接呼び出すことができます。

あなたが行うことができます
sql = ActiveRecord::Base.send(:sanitize_sql_array, ["insert into foo (bar, baz) values (?, ?), (?, ?)", 'a', 'b', 'c', 'd']) 
res = ActiveRecord::Base.connection.execute(sql) 
+2

Jason:これはDBに依存しないより優れたソリューションです。アプリがHerokuにデプロイされている場合、現在受け入れられている解決策(@quest)は機能しません。 –

+7

4年後、 'sanitize_sql_array'とその従兄弟はまだパブリックAPIの一部ではありません。便利な公共の同等物はありますか? –

2

、ここでは一括挿入のためである:ここでは

users_places = [] 
users_values = [] 
timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S') 
params[:users].each do |user| 
    users_places "(?,?,?,?)" 
    users_values << user[:name] << user[:punch_line] << timestamp << timestamp 
end 

bulk_insert_users_sql_arr = ["INSERT INTO users (name, punch_line, created_at, updated_at) VALUES #{users_places.join(", ")}"] + users_values 
begin 
    sql = ActiveRecord::Base.send(:sanitize_sql_array, bulk_insert_users_sql_arr) 
    ActiveRecord::Base.connection.execute(sql) 
rescue 
    "something went wrong with the bulk insert sql query" 
end 

は、それが生成するreference to sanitize_sql_array method in ActiveRecord::Base、あります文字列中の一重引用符をエスケープして適切なクエリ文字列を返します。例えば、punch_lineは "あなたに恋をさせてはいけません"となって、 "あなたを怒らせない"ようになります。

7

あなたは@konusによって投稿ソリューションを使用する場合、あなたはこれを行うことができます発生し、あなたの文字列をラップし、余分な単一引用符たくない場合:これは"O\'Malley"代わりの"'O\'Malley'"

+1

これはSQLからあなたを妨げません注入。 – tvdeyen

+2

@tvdeyen:あなたは、特に受け入れられた答えと比較して、上記のものがどのような形で脆弱であるかを説明しようと思いますか?最終的に、 'quote_string'は使用されている特定のActiveRecordアダプタに依存することになります。 mysql2アダプタと抽象mysqlアダプタの場合、 'quote'は文字列値の' quote_string'を呼び出し、結果を引用符で囲みます。ある種のマルチバイト注入などを考えていますか?ありがとうございました。 – Nathan

+0

ありがとう@Nathan。、それは私のために働く.. –

関連する問題