2011-02-06 14 views
5

Sto cercando una risposta che restituirà un array di oggetti utente tramite (preferibilmente) un named_scope o tramite un metodo di classe sul modello User che esegue alcune manipolazioni.Restituire array di oggetti tramite named_scope - has_many ... appartiene_a associazione; UNION ALL query

Quindi, senza ulteriori indugi ...

Ho due tabelle: utenti e combattimenti.

  • utente ha molte lotte (has_many: combattimenti,: foreign_key => 'challenger_id o challengee_id')
  • Lotta appartiene all'utente (belongs_to: challenger,: class_name => 'utente' ... belongs_to: challengee ,: class_name => 'utente')

lotta ha le seguenti colonne di preoccupazione:

  • challenger_id (user_id fk)
  • chall engee_id (user_id fk)
  • challenger_won (booleano)

Come si può vedere, un utente può essere un challenger o un challengee, ma non entrambi.

  • Se l'utente è uno sfidante e lo sfidante_voce = vero, allora è considerato una vittoria.
  • Se l'utente è una sfida e il challenger_won = falso, allora è considerato una vittoria.
  • Se challenger_won = null, ignorarlo.

Ho una dichiarazione grezzo SQL che restituisce un attributo di caccia (l'user_id) raggruppati per maggior numero di vittorie attributo:

SELECT a.fighter, COUNT(*) AS wins 
    FROM (SELECT challenger_id AS fighter 
      FROM fights 
     WHERE challenger_won = TRUE 
     UNION ALL 
     SELECT challengee_id AS fighter 
      FROM fights 
     WHERE challenger_won = FALSE 
     ) AS a 
GROUP BY a.fighter; 

Quindi, dato queste informazioni, come posso restituire un array di oggetti utente tramite (preferibilmente) un named_scope o tramite un metodo di classe sul modello User che esegue qualche manipolazione?

+0

pensare di cambiare la colonna 'challenger_won' nella' tabella di fights', ad un 'winner_id' (user_id fk) che farà accertamento vince molto più pulito . Potresti quindi avere un 'has_many: wins,: class_name => 'Fight',: foreign_key => 'winner_id'' che ti permetterà di fare' user.wins.count' per trovare le vincite totali – joshnuss

risposta

4

penso che si può provare qualcosa di simile per ricreare il risultato della tua ricerca:

class User 
    named_scope :winners, 
     :select => 'users.*, COUNT(fight.id) AS wins', 
     :join => :fights, 
     :conditions => ['(fights.challenger_id = user_id AND fights.challenger_won = TRUE) OR (fights.challengee_id = user_id AND NOT fights.challenger_won = FALSE)'] 
     :group => 'user_id' 
end 

Tuttavia, per puposes caching, si potrebbe prendere in considerazione l'aggiunta di un campo win_count al modello User. Se crei un metodo setter per il vincitore di un combattimento, puoi incrementare il win_count proprio nel momento in cui cambia.

+0

ah, giusto! Non posso credere di non aver pensato solo ad aggiungere un contatore al modello utente ... questo è sicuramente il miglior approccio ... grazie – keruilin

0

Oppure, senza il join (mysql specifico)

class User 
    named_scope :winners, 
    :select => 'if(challenger_won = FALSE,challenger,challengee) as winner,COUNT(id) AS wins ', 
    :group => 'user_id' 
end 
Problemi correlati