2010-04-28 11 views
1

Je dois afficher un élément d'interface utilisateur (par exemple une étoile ou une coche) pour les employés qui sont «favoris» de l'utilisateur actuel (un autre employé).Requête scalaire Rails

Le modèle employé a la relation suivante définie pour soutenir ceci:

has_and_belongs_to_many :favorites, :class_name => "Employee", :join_table => "favorites", 
    :association_foreign_key => "favorite_id", :foreign_key => "employee_id" 

Les favoris a deux champs: employee_id, favorite_id.

Si je devais écrire SQL, la requête suivante me donner les résultats que je veux: « ? »

SELECT id, account, 
    IF(
    (
    SELECT favorite_id 
    FROM favorites 
    WHERE favorite_id=p.id 
    AND employee_id = ? 
    ) IS NULL, FALSE, TRUE) isFavorite 
FROM  employees 

Lorsque la serait remplacé par la session [: user_id]. Comment représenter la requête scalaire isFavorite dans Rails?

Une autre approche utiliserait une requête comme ceci:

SELECT id, account, IF(favorite_id IS NULL, FALSE, TRUE) isFavorite 
FROM  employees e 
LEFT OUTER JOIN favorites f ON e.id=f.favorite_id 
    AND employee_id = ? 

Encore une fois, le '?' est remplacé par la valeur de la session [: user_id].

J'ai eu un certain succès dans la rédaction de ce Rails: « ? »

ee=Employee.find(:all, :joins=>"LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=1", :select=>"employees.*,favorites.favorite_id") 

Malheureusement, lorsque je tente de faire cette requête « dynamique » en remplaçant le « 1 » avec, je reçois des erreurs.

ee=Employee.find(:all, :joins=>["LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=?",1], :select=>"employees.*,favorites.favorite_id") 

De toute évidence, j'ai la syntaxe erronée, mais peut: les expressions de jointures sont 'dynamiques'? Est-ce un cas pour une expression lambda?

Je souhaite ajouter d'autres filtres à cette requête et l'utiliser avec will_paginate et acts_as_taggable_on, si cela fait une différence.

modifier

erreurs d'essayer de faire :joins dynamique:

ActiveRecord::ConfigurationError: Association named 'LEFT OUTER JOIN favorites ON employees.id=favorites.favorite_id AND favorites.employee_id=?' was not found; perhaps you misspelled it? 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1906:in `build' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1911:in `build' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1910:in `each' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1910:in `build' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/associations.rb:1830:in `initialize' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1789:in `new' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1789:in `add_joins!' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1686:in `construct_finder_sql' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1548:in `find_every' 
    from /Users/craibuc/.gem/ruby/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:615:in `find' 
+0

quelles erreurs obtenez-vous? –

Répondre

3

Essayez ceci:

ee=Employee.all( 
    :select=>"employees.*,favorites.favorite_id", 
    :joins=>"LEFT OUTER JOIN favorites AS favorites 
      ON employees.id=favorites.favorite_id AND 
       favorites.employee_id = #{session[:user_id]}") 

Ou pour être exact:

joins = Employee.send(:sanitize_sql_array, 
      ["LEFT OUTER JOIN favorites AS favorites 
       ON employees.id=favorites.favorite_id AND 
        favorites.employee_id = ? ", session[:user_id] 
      ]) 

ee=Employee.find(:all, 
    :select=>"employees.*,favorites.favorite_id", 
    :joins=> joins) 

deuxième approche porte sur les problèmes d'injection SQL.

Modifier 1

Pour tester ces appels à irb procédez comme suit:

Simuler l'objet de la session en créant hachage:

>> session = {:user_id => "1" } 
session = {:user_id => "1" } 
=> {:user_id=>"1"} 

Execute le viseur:

>> ee=Employee.find(:all, 
     :select=>"employees.*,favorites.favorite_id", 
     :joins=>"LEFT OUTER JOIN favorites AS favorites 
       ON employees.id=favorites.favorite_id AND 
        favorites.employee_id = #{session[:user_id]}") 
+0

La première option fonctionne très bien. Merci. Existe-t-il un moyen de simuler # {session [: user_id]} dans l'IRB? – craig

+0

Merci pour le conseil de session. Je vous voterais une seconde fois si je le pouvais. – craig

0

J'imagine les deux voies sont possibles, mais normalement, je bâton la condition dans la clause WHERE (:conditions):

ee = Employee.find(:all, 
    :select => 'employees.*, favorites.favorite_id', 
    :conditions => ['favorites.employee_id = ?', 1], 
    :joins => 'LEFT OUTER JOIN favorites ON employees.id = favorites.favorite_id' 
) 
+0

La jointure externe gauche renvoie NULL lorsqu'aucune ligne correspondante n'est trouvée. Si vous déplacez la condition à 'where', la logique ne fonctionnera pas comme prévu. –

+0

J'ai essayé cette approche et elle n'a pas, comme le dit KandadaBoggu, retourner les bons résultats. – craig

+0

@Craig: Cela fonctionne-t-il si vous modifiez les conditions à '['favorites.employee_id IS NOT NULL ET favorites.employee_id =?', 1]'? Je demande plus pour ma propre éducation, comme vous avez déjà une réponse. –

0

:joins attend une chaîne brute ou un symbole (asso nom de l'association), ou un tableau d'associations. Vous ne pouvez donc pas avoir de conditions dynamiques là-bas.

Voir la section des paramètres here.