Да, лучше всего использовать named_scope (или метод класса).
Например, если это тотал.рб:
class Total < ActiveRecord::Base
belongs_to :user
belongs_to :total_type
def self.points
joins(:total_type).where(:total_types => {:name => 'points'}).sum(:total)
end
end
и это users.rb:
class User < ActiveRecord::Base
has_many :totals
def method_missing(name, *args, &blk)
if totals.respond_to? name
totals.send(name, *args, &blk)
else
super
end
end
end
затем User.first.points # => 100
Вы могли бы сделать это еще более динамичным ... но за кодом труднее следовать, и если вы не кешируете некоторые вещи, тогда выполняется много ненужных SQL-запросов. Например, total.rb может выглядеть так:
class Total < ActiveRecord::Base
belongs_to :user
belongs_to :total_type
def self.method_missing(name, *args, &blk)
if TotalType.find_by_name(name.to_s)
joins(:total_type).where(:total_types => {:name => name.to_s}).sum(:total)
else
super
end
end
def self.respond_to_missing?(name, priv)
if TotalType.find_by_name(name.to_s)
true
else
super
end
end
end
То есть, когда вызывается User.first.points, вызывается первый пользователь # method_missing, который видит user.totals.respond_to? :точки. Сначала это не так, поэтому вызывается Total :: response_to_missing, который определяет, есть ли тип total_type, называемый 'points'. Есть ... поэтому он вызывается, а затем вызывается Total :: method_missing, который возвращает вам сумму баллов для этого пользователя.
Конечно, вы можете легко кешировать результаты, чтобы ненужные запросы SQL не выполнялись каждый раз, когда user.points вызывается в методах method_missing и response_to_missing, но это просто усложняется, а издержки метода не стоят этого. Менее динамичное решение, которое я предлагал ранее, - это ваша лучшая ставка на то, как ваши модели выложены сейчас.
Надеюсь, это поможет,
1020 * Люк *