Rails 3 Query: Как получить наиболее просматриваемые товары / статьи / что угодно? - PullRequest
1 голос
/ 27 апреля 2011

Мне всегда было интересно, как запрашивать и получать результаты, которые не вписываются в модель. Аналогично тому, как это делается с помощью 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

В основном мне нужно получить список продуктов (желательно просто идентификатор и имя) вместе с количеством просмотров. Очевидно, упорядочено по количеству просмотров desc.

Это 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 ]

3 голосов
/ 09 мая 2011

Вы можете использовать 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 - очень умный способ создания сложных запросов, которые можно использовать повторно независимо от типа базы данных.

2 голосов
/ 10 мая 2011

Внутри метода класса в классе Product:

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

Затем сортируйте его по своему усмотрению.

0 голосов
/ 07 мая 2011

Попробуйте:

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

(Источник - http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html#M000292)

Надеюсь, это поможет!

0 голосов
/ 27 апреля 2011

Я не знаю, есть ли способ сделать это, используя ваши модели. Я бы, наверное, прибегнул к:

Product.connection.select_rows(sql)

Который даст вам массив массивов. Вы можете использовать select_all, если хотите иметь массив хэшей.

...