Rails 4 LIKE sorgu - ActiveRecord fiyat teklifleri ekler


127

Böyle bir sorgu yapmaya çalışıyorum

def self.search(search, page = 1 )
  paginate :per_page => 5, :page => page,
    :conditions => ["name LIKE '%?%' OR postal_code like '%?%'", search, search],   order => 'name'
end

Ancak çalıştırıldığında, sql ifadesinin böyle çıkmasına neden olan bir şey tırnak eklemesidir.

SELECT COUNT(*)
FROM "schools" 
WHERE (name LIKE '%'havard'%' OR postal_code like '%'havard'%')):

Böylece sorunumu görebilirsin. Her ikisini de hiç kullanmadığım Rails 4 ve Postgres 9 kullanıyorum, bu yüzden onun ve aktif bir şey olup olmadığından veya muhtemelen bir postgres şey olup olmadığından emin değilim.

'%my_search%'Son sorguda beğenmek için bunu nasıl kurabilirim ?

Yanıtlar:


228

Yer tutucunuz bir dizeyle değiştirilir ve onu doğru kullanmıyorsunuz.

değiştirmek

"name LIKE '%?%' OR postal_code LIKE '%?%'", search, search

ile

"name LIKE ? OR postal_code LIKE ?", "%#{search}%", "%#{search}%"

6
Bu, SQL Enjeksiyonuna karşı savunmasız değil mi? Demek istediğim, bu searchdizeler sterilize edilmiş mi?
jdscosta91

6
@ jdscosta91 the ?in the in the where will
be

7
@ house9 örnekleri %ve _searchbu yaklaşımın altında, sterilize edilmeyecektir.
Barry Kelly

8
Kullanırken '?' bu şekilde raylarda parametreleştirilmiş bir sorguya dönüştürülür. Parametre içindeki veriler sterilize edilmez (%), ancak sorgudan bağlamı değiştirmek ve işlenmiş SQL ifadelerine dönüştürmek imkansızdır.
David Hoelzer

50

Bunun yerine kullanmanın conditionsRaylar 2'den sözdizimi, kullanım 4'ün Raylar whereyerine yöntemi:

def self.search(search, page = 1 )
  wildcard_search = "%#{search}%"

  where("name ILIKE :search OR postal_code LIKE :search", search: wildcard_search)
    .page(page)
    .per_page(5)
end

NOT: Yukarıdakiler,? Yerine parametre sözdizimini kullanır. yer tutucu: bunların her ikisi de aynı sql'yi oluşturmalıdır.

def self.search(search, page = 1 )
  wildcard_search = "%#{search}%"

  where("name ILIKE ? OR postal_code LIKE ?", wildcard_search, wildcard_search)
    .page(page)
    .per_page(5)
end

NOT: ILIKEad için kullanmak - LIKE'ın büyük / küçük harf duyarlı olmayan postgres sürümü


Bu hala Rails 5 için geçerli mi? Çünkü eğer varsa , ActiveRecord (Rails 5.1.6) tarafından Movie.where("title ILIKE :s", s: search_string)çevrilir SELECT 1 AS one FROM "movies" WHERE (title ILIKE 'test') LIMIT $1- lütfen ILIKE'den sonra yüzde sembolü olmadığına dikkat edin)
sekmo

@sekmo - çalışmalıdır, yüzde search_stringdeğişkene gider . Sanırım SELECT 1 AS oneçıktı sadece ray konsolunda limit(1)mı yoksa siz mi kullanıyorsunuz ? Bilginize: Rails
5.1.6'da

22

Dize enterpolasyonu çalışacak olsa da, sorunuz raylar 4'ü belirttiğinden, bunun için Arel kullanıyor ve uygulama veritabanınızı agnostik tutuyor olabilirsiniz.

def self.search(query, page=1)
  query = "%#{query}%"
  name_match = arel_table[:name].matches(query)
  postal_match = arel_table[:postal_code].matches(query)
  where(name_match.or(postal_match)).page(page).per_page(5)
end

Bunu dinamik olarak bir öznitelik listesiyle yapmak için bir işlev oluşturmak gerçekten kolay olmalı
cevaris

Test edilmemiş, ancak bunun gibi bir şey olabilir: kapsam search_attributes, -> (sorgu, öznitelikler) {arel_attributes = öznitelikler.map {| a | arel_table [a]} arel_queries = arel_attributes.map {| a | a.matches (sorgu)} return where (arel_queries.reduce {| res, q | res.or q})}
Pedro Rolo

8

ActiveRecord, tarafından atıfta bulunulan parametrenin ?bir dize olduğunu bilecek kadar akıllıdır ve bu nedenle onu tek tırnak içine alır. Sen olabilir tek mesaj ped için gerekli olan dize kullanımı Yakut dize interpolasyon anlaşılacağı gibi %semboller. Ancak, bu sizi SQL enjeksiyonuna maruz bırakabilir (bu kötüdür). Dizeyi şu CONCAT()şekilde hazırlamak için SQL işlevini kullanmanızı öneririm :

"name LIKE CONCAT('%',?,'%') OR postal_code LIKE CONCAT('%',?,'%')", search, search)


Bunu bir uygulamada uyguladım ve harika çalıştı. Teşekkür ederim John.
fuzzygroup

Enjeksiyonlarla ilgili olarak, hayır değildir ve her durumda bu bir fark yaratmaz. Dize %sql'ye eklenir ve rails'in daha önce onu doğrulamış olması gerekir (a'nın eklenip eklenmemesi önemli değildir). Ya beklendiği gibi çalışıyor ya da raylarda her iki durumu da etkileyen büyük bir hata var.
estani

5

Deneyin

 def self.search(search, page = 1 )
    paginate :per_page => 5, :page => page,
      :conditions => ["name LIKE  ? OR postal_code like ?", "%#{search}%","%#{search}%"],   order => 'name'
  end

Daha fazla bilgi için AREL koşullarıyla ilgili belgelere bakın .


-1
.find(:all, where: "value LIKE product_%", params: { limit: 20, page: 1 })
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.