137 votes

Rails 4 requête LIKE - ActiveRecord ajoute des guillemets

Je suis en train d'essayer de faire une requête de type like comme ceci

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 cela s'exécute, quelque chose ajoute des guillemets ce qui fait que l'instruction sql ressort comme ceci

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

Donc vous pouvez voir mon problème. Je suis en train d'utiliser Rails 4 et Postgres 9, tous les deux que je n'ai jamais utilisés donc je ne suis pas sûr si c'est une chose d'activerecord ou peut-être une chose de postgres.

Comment puis-je configurer cela pour avoir '%my_search%' dans la requête finale?

252voto

rb512 Points 3157

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

Remplacez

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

par

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

53voto

house9 Points 9240

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

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

NOTE : ce qui précède utilise la syntaxe du paramètre au lieu du paramètre de substitution ?: les deux devraient 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

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

24voto

numbers1311407 Points 15653

Alors que l'interpolation de chaîne fonctionnera, comme votre question spécifie rails 4, vous pourriez utiliser Arel pour cela et garder votre application indépendante de la base de données.

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

8voto

John Cleary Points 61

ActiveRecord est assez intelligent pour savoir que le paramètre auquel fait référence le ? est une chaîne de caractères, et l'encadre donc de guillemets simples. Comme le suggère un article, vous pourriez utiliser l'interpolation de chaînes Ruby pour remplir la chaîne avec les symboles % requis. Cependant, cela pourrait vous exposer à une injection SQL (ce qui est mauvais). Je vous suggère d'utiliser la fonction SQL CONCAT() pour préparer la chaîne de la manière suivante :

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

7voto

mansim Points 368

Si quelqu'un utilise des noms de colonne comme "clé" ou "valeur", alors vous verrez toujours la même erreur indiquant que votre syntaxe de requête mysql est mauvaise. Cela devrait corriger :

.where("`clé` LIKE ?", "%#{clé}%")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X