Учитывая, что вы хотите отсортировать результаты поиска по статистике, добавление счетчиков кешей в модель Restaurant выглядит как ваш лучший вариант.
В случае общего количества посетителей это просто. В случае общего time_spent, это будет немного сложнее, но все же не является неуправляемым. Если вы ищете среднего, то все становится немного сложнее.
Вот код, необходимый для добавления счетчиков в модель вашего ресторана. Обратите внимание, что большая часть нового кода модели находится в модели посетителя.
Добавление новых столбцов в Restaurant
с помощью миграции:
class AddCounterCaches < ActiveRecord::Migration
def self.up
add_column :restaurants, :visitors_count, :integer, :default => 0
add_column :restaurants, :total_time_spent, :integer, :default => 0
Restaurant.reset_column_information
Restaurant.find(:all).each do |r|
count = r.visitors.length
total = r.visitors.inject(0) {|sum, v| sum + v.time_spent}
average = count == 0 ? 0 : total/count
r.update_counters r.id, :visitors_count => count
:total_time_spent => total, :average_time_spent => average
end
end
def self.down
remove_column :restaurants, :visitors_count
remove_column :restaurants, :total_time_spent
end
end
Обновление модели посетителя для обновления кэшей счетчика
class Vistor < ActiveRecord::Base
belongs_to :restaurant, :counter_cache => true
after_save :update_restaurant_time_spent,
:if => Proc.new {|v| v.changed.include?("time_spent")}
def :update_restaurant_time_spent
difference = changes["time_spent"].last - changes["time_spent"].first
Restaurant.update_counters(restaurant_id, :total_time_spent => difference)
restaurant.reload
avg = restaurant.visitors_count == 0 ?
0 : restaurant.total_time_spent / restaurant.visitors_count
restaurant.update_attribute(:average_time_spent, avg)
end
end
Примечание. Код не был проверен, поэтому он может содержать незначительные ошибки.
Теперь вы можете сортировать по этим столбцам, создавать именованные области, которые включают их, или использовать их в ваших методах.