ArelとRailsでLIKEクエリを行う方法は?


115

私は次のようなことをしたいです:

SELECT * FROM USER WHERE NAME LIKE '%Smith%';

アレルでの私の試み:

# params[:query] = 'Smith'
User.where("name like '%?%'", params[:query]).to_sql

ただし、これは次のようになります。

SELECT * FROM USER WHERE NAME LIKE '%'Smith'%';

Arelはクエリ文字列 'Smith'を正しくラップしますが、これはLIKEステートメントであるため機能しません。

ArelでLIKEクエリを実行するにはどうすればよいですか?

PSボーナス-実際には、名前と説明の両方のテーブルの2つのフィールドをスキャンして、クエリに一致するものがないか確認しています。それはどのように機能しますか?


1
ボーナスのアールアンサーを更新しました。
ペドロロロ2014年

回答:


275

これはarelでlikeクエリを実行する方法です。

users = User.arel_table
User.where(users[:name].matches("%#{user_name}%"))

PS:

users = User.arel_table
query_string = "%#{params[query]}%"
param_matches_string =  ->(param){ 
  users[param].matches(query_string) 
} 
User.where(param_matches_string.(:name)\
                       .or(param_matches_string.(:description)))

10
を使用するwhere("name like ?", ...)場合とは異なり、このアプローチは異なるデータベース間でより移植性があります。たとえばILIKE、Postgres dbに対するクエリで使用されます。
dkobozev

20
これはSQLインジェクションから保護されていますか?
スレン2012年

7
これは、SQLインジェクションから完全には保護されません。user_nameを "%"に設定してみてください。クエリは一致を返します
travis-146

5
私はparamsを直接使用してsql injectをUser.where(users[:name].matches("%#{params[:user_name]}%"))試行しましたがTRUNCATE users;、他のそのようなクエリを試行しましたが、sql側では何も起こりませんでした。安全に見えます。
earlonrails 2013

5
.gsub(/[%_]/, '\\\\\0')MySqlワイルドカード文字をエスケープするために使用します。
aercolino 2013

116

試す

User.where("name like ?", "%#{params[:query]}%").to_sql

PS。

q = "%#{params[:query]}%"
User.where("name like ? or description like ?", q, q).to_sql

Aaandは久しぶりですが、@ cgg5207は変更を加えました(長い名前のパラメーターまたは複数の長い名前のパラメーターを検索する場合、またはタイプするのが面倒な場合に最も役立ちます)。

q = "%#{params[:query]}%"
User.where("name like :q or description like :q", :q => q).to_sql

または

User.where("name like :q or description like :q", :q => "%#{params[:query]}%").to_sql

9
Rails %は置換された文字列でエスケープしないことをどのように知っていますか?片側のみのワイルドカードが必要な場合、ユーザーが%両端を含むクエリ値を送信するのを妨げるものは何もないようです(実際には、Rails %はクエリ文字列に表示されないようにしていますが、これをActiveRecordレベルで保護する必要があります)。
スティーブン

8
これはSQLインジェクション攻撃に対して脆弱ではありませんか?
Behrang Saeedzadeh 11'14 / 11/11

7
@Behrang no 8)User.where( "%#{params [:query]}%などの名前または%#{params [:query]}%")。to_sqlのような説明は脆弱ですが、表示される形式では、Railsはparams [:query]をエスケープします
Reuben Mallaby

オフトピックでごめんなさい。私はメソッドto_sqlまたはアールマネージャーのsql gitを持っています、dbでsqlを実行する方法は?
МалъСкрылевъ

Model.where(to_sql_result)
Pedro Rolo

4

Reuben Mallabyの答えは、パラメーターバインディングを使用するようにさらに短くできます。

User.where("name like :kw or description like :kw", :kw=>"%#{params[:query]}%").to_sql
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.