Evitare le chiamate individuali del database per il conteggio
-
27-10-2019 - |
Domanda
I miei modelli sembrano così:
class Movie < ActiveRecord::Base
attr_accessible :title, :year, :rotten_id, :audience_score,
:critics_score, :runtime, :synopsis, :link, :image
has_many :jobs, :dependent => :destroy
has_many :actors, :through => :jobs
end
class Actor < ActiveRecord::Base
attr_accessible :name
has_many :movies, :through => :jobs
has_many :jobs, :dependent => :destroy
end
class Job < ActiveRecord::Base
attr_accessible :movie_id, :actor_id
belongs_to :movie
belongs_to :actor
end
Quando mostro il mio indice di attori, vorrei mostrare il numero di film ogni attore ha recitato. Posso farlo con @actor.movies.count
, Tuttavia, questo genera una query SQL per each actor
. Con, diciamo, 30 attori, ciò comporterà 30 domande extra oltre alle iniziali.
Esiste un modo per includere il conteggio dei film a cui ogni attore ha partecipato, nella iniziale Actor.all
chiamata? E quindi fare le cose con una sola chiamata. Bonus extra se questo è stato ordinato con detto conteggio.
Aggiornare:Tutte le risposte fornite sono state utili e sebbene si sia trasformata in un po 'di slitting a un certo punto, ha funzionato bene. Ho fatto un miscuglio di tutti i tuoi suggerimenti. Ho aggiunto una colonna Film_Counter al mio modello attore. Nel mio modello di lavoro ho aggiunto belongs_to :actor, :counter_cache => :movies_counter
. Funziona brillantemente e viene automaticamente aggiornato quando creo o distruggo un film, senza che io aggiunga ulteriore codice.
Soluzione
Come ha notato @Sam, dovresti aggiungere una nuova colonna a actors
tavolo movies_counter
rails g migration add_movies_counter_to_actor movies_counter:integer
Ora puoi modificare la tua migrazione
class AddMoviesCounterToActor < ActiveRecord::Migration
def self.up
add_column :actors, :movies_counter, :integer, :default => 0
Actor.reset_column_information
Actor.all.each do |a|
a.update_attribute :movies_counter, a.movies.count
end
end
def self.down
remove_column :actors, :movies_counter
end
end
E eseguilo
rake db:migrate
Quindi dovresti aggiungere due callback: after_save
e after_destroy
class Movie < ActiveRecord::Base
attr_accessible :title, :year, :rotten_id, :audience_score,
:critics_score, :runtime, :synopsis, :link, :image
has_many :jobs, :dependent => :destroy
has_many :actors, :through => :jobs
after_save :update_movie_counter
after_destroy :update_movie_counter
private
def update_movie_counter
self.actors.each do |actor|
actor.update_attribute(:movie_count, actor.movies.count)
end
end
end
Quindi puoi chiamare some_actor.movies_counter
Altri suggerimenti
Aggiungi una colonna al tavolo dell'attore chiamato "Movie_Count". Quindi aggiungi una chiamata nel modello del tuo attore che aggiorna quella colonna.
class Movie < ActiveRecord::Base
has_many :actors, :through => :jobs
before_save :update_movie_count
def update_movie_count
self.actor.update_attribute(:movie_count, self.movies.size)
end
end
In questo modo hai solo un numero intero che viene aggiornato invece di chiamare tutti i record.