Arel ve Rails'de LIKE sorgusu nasıl yapılır?


115

Şunun gibi bir şey yapmak istiyorum:

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

Arel'deki girişimim:

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

Ancak bu şu olur:

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

Arel, 'Smith' sorgu dizesini doğru bir şekilde sarar, ancak bu bir LIKE ifadesi olduğu için çalışmaz.

Arel'de LIKE sorgusu nasıl yapılır?

PS Bonus - Sorguyla herhangi bir eşleşme olup olmadığını görmek için tablodaki hem ad hem de açıklama olmak üzere iki alanı taramaya çalışıyorum. Bu nasıl çalışır?


1
Bonus için arel cevabını güncelledim.
Pedro Rolo

Yanıtlar:


275

Arel'de benzer bir sorguyu şu şekilde gerçekleştirirsiniz:

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

Not:

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
Kullanmanın aksine where("name like ?", ...), bu yaklaşım farklı veritabanları arasında daha taşınabilirdir. Örneğin, ILIKEPostgres db'ye karşı bir sorguda kullanılmasıyla sonuçlanır .
dkobozev

20
bu SQL enjeksiyonlarına karşı korumalı mı?
sren

7
Bu, SQL enjeksiyonuna karşı tam koruma DEĞİLDİR. User_name'i "%" olarak ayarlamayı deneyin. Sorgu maçları döndürecek
travis-146

5
Doğrudan parametreleri kullanarak sql enjekte User.where(users[:name].matches("%#{params[:user_name]}%"))etmeye çalıştım, denedim TRUNCATE users;ve diğer bu tür sorgular ve sql tarafında hiçbir şey olmadı. Bana güvenli görünüyor.
earlonrails

5
.gsub(/[%_]/, '\\\\\0')MySql joker karakterlerinden kaçmak için kullanın .
aercolino

116

Deneyin

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

PS.

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

Aa ve uzun zaman oldu ama @ cgg5207 bir değişiklik ekledi (çoğunlukla uzun isimli veya birden fazla uzun isimli parametre arayacaksanız veya yazmak için çok tembelseniz yararlıdır)

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

veya

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

9
Rails %değiştirilen dizede kaçmamayı nasıl biliyor ? Görünüşe göre sadece tek taraflı bir joker karakter istediyseniz, kullanıcının %her iki ucunu da içeren bir sorgu değeri göndermesini engelleyen hiçbir şey yok (pratikte Rails'in %bir sorgu dizesinde görünmesini engellediğini biliyorum , ancak orada gibi görünüyor buna karşı ActiveRecord düzeyinde koruma olmalıdır).
Steven

8
Bu, SQL enjeksiyon saldırılarına karşı savunmasız değil mi?
Behrang Saeedzadeh

7
@Behrang no 8) User.where ("% # {params [: sorgu]}% gibi ad veya% # {params [: sorgu]}% gibi açıklama"). To_sql savunmasız olabilir, ancak benim gösterdiğim formatta , Rails parametrelerden kaçar [: sorgu]
Reuben Mallaby

Offtopik için özür dilerim. Metodun sql to_sqlgit'ine veya arel yöneticisine sahibim, sql'yi db'de nasıl çalıştırabilirim?
Малъ Скрылевъ

Model.where (to_sql_result)
Pedro Rolo

4

Reuben Mallaby'nin yanıtı, parametre bağlamalarını kullanmak için daha da kısaltılabilir:

User.where("name like :kw or description like :kw", :kw=>"%#{params[:query]}%").to_sql
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.