我正在尝试从AREL获取sql,但是如果我使用average(:stars),它不起作用:
这样做:
Review.where("reviewed_user_id = ?",self.reviewed_user_id).to_sql #=> "SELECT `reviews`.* FROM `reviews` WHERE (reviewed_user_id = 3)"
这会导致NoMethodError:
Review.where("reviewed_user_id = ?",self.reviewed_user_id).average(:stars).to_sql #=> undefined method `to_sql' for 3:Fixnum
解决方法
原因是因为平均方法是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"