Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1577 connectés 

  FORUM HardWare.fr
  Programmation
  Ruby/Rails

  Requête sql dynamique

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Requête sql dynamique

n°1809839
sundevil
Posté le 08-11-2008 à 14:42:20  profilanswer
 

Bonjour à tous,
 
J'aimerais réaliser un petit moteur de recherche pour mon site mais je fais fasse à un problème.
Pour ce moteur, plusieurs champs de recherche sont disponible. En fonction des champs remplit par l'utilisateur, ma requête évolue donc, et c'est la que le problème survient.
 
Je voulais utilisé la méthode classique:
 
User.find(:all, :conditions => ['name = ?', name])
 
Mais je ne vois pas comment fait évoluer cette méthode de manière dynamique afin de rentrer les conditions en fonction de mes champs.
Exemple:
Si le nom de l'utilisateur recherche et son sexe est remplit, je voudrais un truc du genre:
 
User.find(:all, :conditions => ['name = ? AND sexe = ?', name, sexe])
 
Mais comment faire cela dynamiquement ?
 
J'ai essayé avec sql_conditions, mais visiblement, ça ne marche pas très bien avec la méthode que j'ai utilisé:
 
    sql_conditions << [' AND sexe = ? ', @sexe] if !@sexe.nil?
    sql_conditions << [' AND name = ? ', @name]
 
Il me dit "can't convert Array into String".
 
Je veux utiliser les ? pour éviter les sql injections.
 
Quelqu'un peut il m'aider ?
 
Merci.

mood
Publicité
Posté le 08-11-2008 à 14:42:20  profilanswer
 

n°1809926
esox_ch
Posté le 08-11-2008 à 19:23:36  profilanswer
 

Salut,
 
Personnellement j'ai résolu ça de la manière suivante :  
 
 

Code :
  1. # Builds a list based on pagination and sort fields
  2.  def build_list model,conditions=nil,order=nil,items_per_page=nil
  3.    sort = order.downcase unless order.nil?
  4.    sort = (sort =~ /^.+_reverse$/) ? sort.gsub('_reverse','')+' DESC' : sort
  5.    
  6.    
  7.    unless conditions.nil? || conditions[:field].nil? || conditions[:query].nil?
  8.      search_fields = conditions[:field]
  9.      search_values = conditions[:query]
  10.      
  11.      # Check that all the search_fields are valid by comparing them with the attributs of the element
  12.      
  13.      invalid_field = false
  14.      search_fields.each do |field|
  15.        invalid_field = true  unless model.columns_name_hash.value? field.downcase
  16.      end
  17.      
  18.      # If one or more of the search fields don't match with the attributs, the method returns the "normal" list.
  19.      if invalid_field
  20.        conditions=nil
  21.      else
  22.        conditions = ["#{search_fields} LIKE ?", "%#{search_values}%"]
  23.      end
  24.    else
  25.      conditions=nil
  26.    end
  27.    
  28.    elements = nil;
  29.    total = nil;
  30.    
  31.    if items_per_page.nil?
  32.      elements = model.find(:all, :order=>sort,:conditions=>conditions)
  33.    else
  34.      total = model.count(:conditions => conditions)
  35.      elements = model.paginate :page => params[:page], :order => sort, :conditions => conditions, :per_page => items_per_page
  36.    end
  37.    
  38.    return total,elements
  39.  end


 
En gros, je garde la syntaxe avec le ? pour éviter les injections SQL. Mais afin d'éviter qu'on me joue des tours en détournant le nom des champs sur lesquels j'effectue mes recherches, je check qu'ils appartiennent aux champs définis dans le Model en question (lignes 15-18)


---------------
Si la vérité est découverte par quelqu'un d'autre,elle perd toujours un peu d'attrait
n°1842126
igarimasho
Posté le 23-01-2009 à 15:58:41  profilanswer
 

Quelqu'un a des bonnes sources et des tutoriaux sur la "reflection", parce qu'en fait avant je faisais comment vous, mais c'est super crado. J'arrive pas à invoquer des méthodes dynamiquement à la suite comme par exemple:
 
User.find_by_login(login).valid.author
 
Comment ils font dans Rails? C'est tout des named_scope?

n°1842171
esox_ch
Posté le 23-01-2009 à 16:46:29  profilanswer
 

J'ai pas trop compris là question. Tu veux faire quoi exactement?


---------------
Si la vérité est découverte par quelqu'un d'autre,elle perd toujours un peu d'attrait
n°1842245
igarimasho
Posté le 23-01-2009 à 18:48:17  profilanswer
 

En fait générer dynamiquement une seule méthode et l'invoquer je sais faire:
 
Ce que j'arrive pas à faire c'est par exemple exécuter dynamiquement plusieurs méthodes les unes à la suite des autres:

Code :
  1. User.date(start_date, end_date).login(login)


ou

Code :
  1. User.date(start_date, end_date).login(login).group(group_id)


date, login et group sont des named_scope et je veux les invoquer de manière conditionelle si leur paramètre est passé. Faire une boucle avec la méthode send ne marche pas, car les méthodes sont exécutées indépendemment les unes des autres.


Message édité par igarimasho le 23-01-2009 à 18:50:43
n°1842306
igarimasho
Posté le 23-01-2009 à 20:03:37  profilanswer
 

Si j'ai bien compris, ça devrait être dispo pour Rails 2.3 ou 3 : http://ryandaigle.com/articles/200 [...] pe-methods
 
Sinon si tu veux just dynamiquement générer des critères de recherche qui porte sur un seul model, tu peux faire comme ça:
Dans mon cas j'ai nécessairement une recherche par site

Code :
  1. def self.super_finder(site_id, search = {})
  2.   find_methods = "find_by_site_id"
  3.   arguments = [site_id]
  4.  
  5.   if search
  6.     find_methods << "_and_login" and arguments << search[:login] if !search[:login].empty?
  7.     find_methods << "_and_id" and arguments << search[:id] if !search[:id].empty?
  8.   end
  9.   send(find_methods.to_sym, *arguments)
  10. end


 
Dans mon controlleur, je l'appelle avec: User.super_finder(site_id, search). Donc si en paramètre de recherche je ne mets rien, ça me génère:

Code :
  1. User.find_by_site_id(site_id)


 
Si en paramètre je passe login et id, ça me génére dynamiquement:

Code :
  1. User.find_by_site_id_and_login_and_id(site_id, login, id)


C'est plus propre non?  :)
 
La limite, c'est qu'il faut que les critères de recherche porte sur le même Model. Donc par exemple:

Code :
  1. User.find_by_site_id_and_login


ça marche nickel. Mais par exemple si je dois ajouter un critère qui porte sur un champ d'une table jointe, ça ne marche plus, par exemple:

Code :
  1. User.find_by_site_and_book_title


Dans ce cas il faut utiliser un named_scope, malheureusement je ne sais pas comment faire par exemple un truc du genre:

Code :
  1. find_by_site_id(site_id).booktitle(booktitle)


 
EDIT: le module NamedScope possède une méthode scoped qui m'a l'air importante pour ce que je veux faire. D'ailleurs dans le patch Rails pour les named_scope dynamique c'est ce qui est utilisé, j'ai regardé le code source:  
http://api.rubyonrails.org/classes [...] Scope.html
http://github.com/rails/rails/comm [...] 287afe2b55


Message édité par igarimasho le 23-01-2009 à 20:27:27
n°1842321
igarimasho
Posté le 23-01-2009 à 21:23:14  profilanswer
 

Sinon une manière fort élégante de faire cette fameuse recherche par critère et qui utilise scoped: http://railscasts.com/episodes/112-anonymous-scopes
 
Il est fort ce Ryan Bates, et j'aime bien regarder le code source de son site railscasts  :D
 
 
Sinon pour exécuter des méthodes à la chaîne il y a la méthode Kernel#eval qui exécute un String comme si c'était du code Ruby, à utiliser avec beaucoup de précautions donc.


Message édité par igarimasho le 23-01-2009 à 21:38:11
n°1842337
esox_ch
Posté le 23-01-2009 à 22:14:25  profilanswer
 

D'accord :D
Pour le moment j'avais jamais eu besoin, mais c'est clair ça peut le faire :o
 
Par contre, je suis contre l'utilisation de Kernel#eval .. à mon avis ça doit être vraiment utilisé en dernier ressort ..


---------------
Si la vérité est découverte par quelqu'un d'autre,elle perd toujours un peu d'attrait

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Ruby/Rails

  Requête sql dynamique

 

Sujets relatifs
requete mysql categorie et sous cat affichage des produitsrequête mysql : insert into where exists ?
[Résolu] Menu et sous menu-dynamiqueRequete web dynamique (VBA)
[MySQL v5] [Procédure Stockée] construire une requête dynamique ?JDBC, déclaration dynamique des requête SQL ?
SQL - requête sur nom de variable générée de façon dynamiqueerreur avec pl/sql , requete dynamique
Colonne dynamique dans une requête [SQL Server 2000 - Transact SQL][PHP] Variable dynamique et bouclage de requête
Plus de sujets relatifs à : Requête sql dynamique


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR