Можно ли заставить ActiveRecord создавать объекты для строк, загруженных с помощью параметра: joins? - PullRequest
5 голосов
/ 14 февраля 2009

Мне нужно сделать что-то вроде этого

class User < ActiveRecord::Base
  has_many :abuse_reports
end

class AbuseReport < ActiveRecord::Base
  belongs_to :abuser, :class_name => 'User', :foreign_key => 'abuser_id'
  belongs_to :game
end

class Game < ActiveRecord::Base
  has_many :abuse_reports
end

@top_abusers = User.page(params[:page], 
  :joins => [
    'JOIN abuse_reports ON users.id = abuse_reports.abuser_id', 
    'JOIN games ON games.id = abuse_reports.game_id'
  ], 
  :group => 'users.id',
  :select => 'users.*, count(distinct games.id) AS game_count, count(abuse_reports.id) as abuse_report_count',
  :order => 'game_count DESC, abuse_report_count DESC'
)

Это работает, но не создает объекты для AbuseReports или Games - оно просто возвращает кучу строк. Когда я ссылаюсь на эти объекты с моей точки зрения, он загружает их снова. Есть ли способ это исправить? Или какой-нибудь способ получить это поведение без использования: joins?

Ответы [ 2 ]

11 голосов
/ 15 февраля 2009

Во-первых, вы действительно должны использовать: include вместо: joins

User.find(:all, :include => { :abuse_reports => [ :game ] }, :order => )

или, в вашем случае, попробуйте

User.page(params[:page], :include => { :abuse_reports => [ :game ] })

Это будет выполнять объединение для вас и извлекать записи одним выстрелом.

Теперь, это может получить определенную запись игры для вас несколько раз (если одна и та же игра связана с пользователем несколькими отчетами.) Если ваша запись игры велика, вы можете уменьшить объем данных, которыми обмениваются ваше приложение и СУБД выглядит следующим образом:

class User < ActiveRecord::Base
  has_many :abuse_reports
  has_many :abused_games, :through => :abuse_reports
end
...

User.find(:all, :include => [ :abuse_reports, :abused_games ])

Наконец, вы также хотите получить количество и отсортировать их соответственно. Ознакомьтесь с http://railscasts.com/episodes/23, чтобы узнать, как добавить счетчики кэшей в реальные активные записи (счетчики кэшей упрощают SQL и облегчают жизнь СУБД, а ваши запросы выполняются быстрее). После того, как вы настроите счетчики кэшей, вы можете, наконец, изменить вышеописанное, чтобы сделать:

User.find(:all, :include => [ :abuse_reports, :abused_games ], :order => 'users.abused_games_count DESC, users.abuse_reports_count DESC')

Это в конечном итоге извлечет ваши ActiveRecords в одну одну , простую инструкцию SQL.

3 голосов
/ 14 февраля 2009

Проблема, с которой вы столкнулись, заключается в том, что вы используете ActiveRecord таким образом, чтобы его «не предполагалось» использовать. Под этим я подразумеваю, что вы пишете свой собственный sql, что заставляет AR передать вам весь свой контроль.

Если вы хотите, чтобы AR обрабатывал все, вы должны попытаться использовать его с меньшим количеством собственного SQL. Похоже, вы хотите знать, какой пользователь имеет наибольшее количество AbuseReports. Попробуйте что-то вроде этого:

some_user.abuse_reports.count

чтобы получить количество злоупотреблений_отчетов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...