web-dev-qa-db-fra.com

Rails 4 Requête LIKE - ActiveRecord ajoute des guillemets

J'essaie de faire une requête similaire comme si

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

Mais quand il est lancé, quelque chose est en train d’ajouter des guillemets, ce qui provoque l’instruction SQL de sortir comme si

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

Donc, vous pouvez voir mon problème. J'utilise Rails 4 et Postgres 9 que je n'ai jamais utilisés, donc je ne suis pas sûr qu'il s'agisse d'une opération activerecord ou éventuellement postgres.

Comment puis-je configurer cela alors j'ai comme '%my_search%' dans la requête finale?

119
Harry Forbess

Votre espace réservé est remplacé par une chaîne et vous ne le gérez pas correctement.

Remplacer

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

avec

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

Au lieu d'utiliser la syntaxe conditions de Rails 2, utilisez plutôt la méthode Rails 4 de where:

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

Remarque: ce qui précède utilise la syntaxe de paramètre au lieu de? espace réservé: ces deux doivent générer le même sql.

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

REMARQUE: utilisation de ILIKE pour le nom - version de LIKE insensible à la casse

50
house9

Bien que l'interpolation de chaîne fonctionne, comme votre question le spécifie Rails 4, vous pourriez utiliser Arel à cet effet et maintenir votre base de données d'applications agnostique.

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
21
numbers1311407

ActiveRecord est assez intelligent pour savoir que le paramètre référencé par le ? est une chaîne et qu'il est donc entouré de guillemets simples. Vous pourriez comme le suggère un message utilisez l’interpolation de chaîne Ruby pour garnir la chaîne avec les symboles % requis. Cependant, cela pourrait vous exposer à l'injection SQL (ce qui est mauvais). Je vous suggère d'utiliser la fonction SQL CONCAT() pour préparer la chaîne comme suit:

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

7
John Cleary

Essayer

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

Voir les docs sur les conditions AREL pour plus d'informations.

5
tihom