Ответ 1
Причина, по которой это происходит, заключается в том, что средний метод находится на ActiveRecord::Relation
, а не на Arel, что заставляет вычислять.
m = Review.where('id = ?', 42).method(:average)
#=> #<Method: ActiveRecord::Relation(ActiveRecord::Calculations)#average>
m.source_location # or m.__file__ if you're on a different version of Ruby
#=> ["/Users/jtran/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.4/lib/active_record/relation/calculations.rb", 65]
Проверяя внутренние элементы ActiveRecord::Calculations
, вы можете узнать, как получить доступ к SQL, который он использует.
my_reviewed_user_id = 42
relation = Review.where('reviewed_user_id = ?', my_reviewed_user_id)
column = Arel::Attribute.new(Review.unscoped.table, :stars)
relation.select_values = [column.average]
relation.to_sql
#=> "SELECT AVG(\"reviews\".\"stars\") AS avg_id FROM \"reviews\" WHERE (reviewed_user_id = 42)"
Осторожно, если вы работаете на консоли. ActiveRecord::Relation
кэширует вещи, поэтому, если вы введете это в консоль по строкам, это фактически не сработает, потому что довольно-печатная сила вынуждает отношение. Однако разделение выше на точки с запятой и никаких новых строк будет работать.
В качестве альтернативы вы можете напрямую использовать Arel, например:
my_reviewed_user_id = 42
reviews = Arel::Table.new(:reviews)
reviews.where(reviews[:reviewed_user_id].eq(my_reviewed_user_id)).project(reviews[:stars].average).to_sql
#=> "SELECT AVG(\"reviews\".\"stars\") AS avg_id FROM \"reviews\" WHERE \"users\".\"reviewed_user_id\" = 42"