2009-02-14 9 views
5

muszę zrobić coś takiegoCzy jest możliwe, aby ActiveRecord tworzył obiekty dla wierszy załadowanych przy użyciu opcji: join?

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' 
) 

To działa, ale nie tworzyć obiekty dla AbuseReports lub Games - to po prostu zwraca stos rzędów. Kiedy odwołuję się do tych obiektów z mojego widoku, ładuje je ponownie. Czy istnieje sposób, aby to naprawić? Lub jakiś sposób, aby uzyskać to zachowanie bez użycia: join?

+0

@jimgreer, wszelkie postępy w tym wydaniu? – vladr

Odpowiedz

3

Problem polega na tym, że używasz ActiveRecord w sposób, w jaki nie jest on "używany". Rozumiem przez to, że piszesz własny sql, który sprawia, że ​​AR oddaje Ci całą swoją kontrolę.

Jeśli AR ma obsłużyć wszystko, powinieneś spróbować użyć go z mniejszą ilością własnego kodu SQL. Wygląda na to, że chcesz wiedzieć, który użytkownik ma największą liczbę AbuseReports. Spróbuj czegoś takiego:

some_user.abuse_reports.count 

aby uzyskać liczbę abuse_reports

11

Po pierwsze, trzeba naprawdę użyć: include zamiast: dołącza

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

lub, w danym przypadku, spróbuj

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

Spowoduje to wykonanie połączenia dla ciebie i odzyskaj rekordy w jednym ujęciu.

Teraz może pobrać dla ciebie dany rekord gry wiele razy (jeśli ta sama gra jest powiązana z użytkownikiem przez wiele raportów). Jeśli twój rekord gry jest duży, możesz zmniejszyć ilość danych wymienianych między aplikacją i RDBMS w następujący sposób:

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

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

Wreszcie, chcesz również pobrać liczby i odpowiednio sortować. Zapoznaj się z http://railscasts.com/episodes/23, aby dowiedzieć się, jak dodać bufory liczników do rzeczywistych aktywnych rekordów (bufory liczników upraszczają SQL i ułatwiają życie RDBMS, a zapytania działają szybciej). Po skonfigurowaniu bufory licznika, można wreszcie zmienić powyższe zrobić:

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

To ostatecznie odzyskać ActiveRecords w jednym pojedynczy, prosty SQL.

Powiązane problemy