Rails 3查询:如何获得最受欢迎的产品/文章/什么?

时间:2011-04-26 21:01:04

标签: activerecord arel ruby-on-rails-3

我总是想知道如何查询并获得不适合模型的结果。类似于如何使用LINQ并投射到匿名对象中。

所以这是简单的架构:

# Product.rb
class Product < ActiveRecord::Base
   has_many :product_views

   # attributes: id, name, description, created_at, updated_at
end

# ProductView.rb
class ProductView < ActiveRecord::Base
   belongs_to :product

   # attributes: id, product_id, request_ip, created_at, updated_at
end

基本上我需要获得一个产品列表(最好是id和name)以及它拥有的视图数量。显然按照查看次数排序。

这是我想要的SQL:

select 
    p.id,
    p.name,    
    count(pv.product_id) as views
from 
    product_views pv
inner join
    products p on pv.product_id = p.id
group by
    pv.product_id
order by
    count(product_id) desc

我尝试了以下类似的东西,但是我得到了ProductView对象,我想得到一个数组或其他任何东西。

ProductView.includes(:product)
           .group('product_id')
           .select("products.id, products.name, count(product_id)")

使用纯SQL或LINQ这种事情是微不足道的,但我发现自己在Rails中遇到了这种查询。也许我没有想到着名的“铁路方式”,也许我错过了一些明显的东西。

那么你如何在Rails 3中进行这种查询,特别是这个?任何改善我这样做的建议都是值得欢迎的。

谢谢

4 个答案:

答案 0 :(得分:3)

你可以使用Arel来做你想要的事情:

products = Product.arel_table
product_views = ProductView.arel_table

# expanded for readability:
sql = products.join(product_views)
              .on(product_views[:product_id].eq(product[:id]))
              .group(product_views[:product_id])
              .order('views DESC')
              .project(products[:id],
                       products[:name],
                       product_views[:id].count.as('views'))

products_with_views = Product.connection.select_all(sql.to_sql) # or select_rows to just get the values

是的,它很长,但Arel是一种非常聪明的方法来处理创建复杂的查询,无论数据库类型如何都可以重复使用。

答案 1 :(得分:2)

在Product类的类方法中:

Product.includes(:product_views).all.map { |p| [p.id, p.name, p.product_views.size] }

然后根据需要对其进行排序。

答案 2 :(得分:0)

我不知道是否有办法使用你的模型。我可能会诉诸:

Product.connection.select_rows(sql)

这将为您提供一组数组。如果您想要一组哈希值,可以使用select_all

答案 3 :(得分:-1)

试试这个:

@product = Product.find(#product_id)
@product_views = @product.product_views.count

(来源 - http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html#M000292

希望这有帮助!