Возврат массива объектов через named_scope - has_many ... own_to association; UNION ALL запрос - PullRequest
5 голосов
/ 06 февраля 2011

Я ищу ответ, который вернет массив пользовательских объектов через (предпочтительно) named_scope или через метод класса в модели User, которая выполняет некоторые манипуляции.

Так что без дальнейших церемоний ...

У меня есть две таблицы: пользователи и бои.

  • У пользователя много боев (has_many: fights,: foreign_key => 'challengeer_id или challengee_id')
  • Бой принадлежит пользователю (own_to: challengeer,: class_name => 'Пользователь' ... own_to: challengee,: class_name => 'User')

Бой имеет следующие столбцы проблемы:

  • challengeer_id (user_id fk)
  • challengee_id (user_id fk)
  • challengeer_won (булево)

Как видите, пользователь можетбыть претендентом или претендентом, но не обоими.

  • Если пользователь является претендентом, аallenger_won = true, то это считается победой.
  • Если пользователь являетсяChallenger и Challenger_Won = false, то это считается победой.
  • Еслиthe challengeer_won = null, затем просто проигнорируйте его.

У меня есть необработанный оператор SQL, который возвращает атрибут истребителя (user_id), сгруппированный по атрибуту большинства побед:

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;

Итакучитывая эту информацию, как я могу вернуть массив пользовательских объектов через (предпочтительно) named_scope или через метод класса в модели User, которая выполняет некоторые манипуляции?

Ответы [ 2 ]

4 голосов
/ 10 февраля 2011

Я думаю, вы можете попробовать что-то вроде этого, чтобы воссоздать результат вашего запроса:

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

Однако для целей кэширования вы можете рассмотреть возможность добавления поля win_count в модель User. Если вы создадите метод сеттера для победителя боя, вы можете увеличить win_count прямо в тот момент, когда он изменится.

0 голосов
/ 10 февраля 2011

Или без объединения (специфично для mysql)

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