Как вывести уникальные записи из Много через отношения?
мне интересно, каков наилучший способ отображения уникальных записей из has_many, через отношения в Rails3.
у меня есть три модели:
class User < ActiveRecord::Base
has_many :orders
has_many :products, :through => :orders
end
class Products < ActiveRecord::Base
has_many :orders
has_many :users, :through => :orders
end
class Order < ActiveRecord::Base
belongs_to :user, :counter_cache => true
belongs_to :product, :counter_cache => true
end
допустим, я хочу перечислить все продукты, которые клиент заказал на своей странице показа.
Они, возможно, заказали некоторые продукты несколько раз, поэтому я использую counter_cache для отображения в порядке убывания ранга, в зависимости от количества заказов.
но, если они заказали продукт несколько раз, мне нужно убедиться, что каждый продукт указан только один раз.
@products = @user.products.ranked(:limit => 10).uniq!
работает, когда есть несколько записей заказа для продукта, но генерирует ошибку, если продукт был заказан только один раз. (ранжирование-это пользовательская функция сортировки, определенная в другом месте)
Другой альтернативой является:
@products = @user.products.ranked(:limit => 10, :select => "DISTINCT(ID)")
Я не уверен, что я на правильном подходе здесь.
кто-нибудь еще занимался этим? С какими проблемами вы столкнулись? Где я могу узнать больше о разнице между ними .уникальный! и отчетливый ()?
каков наилучший способ создания списка уникальных записей через has_many, через отношения?
спасибо
3 ответа:
вы пытались указать параметр: uniq в ассоциации has_many:
has_many :products, :through => :orders, :uniq => true
:uniq
если true, дубликаты будут опущены из коллекции. Полезно в сочетании с :через.
ОБНОВЛЕНИЕ ДЛЯ RAILS 4:
В Rails 4,
has_many :products, :through => :orders, :uniq => true
устарела. Вместо этого, теперь вы должны написатьhas_many :products, -> { distinct }, through: :orders
. Смотрите distinct Раздел для связей типа has_many: через отношения с документацией организаций и ActiveRecord для получения дополнительной информации. Спасибо Курту Мюллеру за то, что он указал на это в своем комментарии.
отметим, что
uniq: true
был удален из допустимых вариантовhas_many
по состоянию на рельсы 4.в Rails 4 Вы должны предоставить область для настройки такого поведения. Области могут поставляться через лямбды, например:
has_many :products, -> { uniq }, :through => :orders
руководство rails охватывает этот и другие способы использования областей для фильтрации запросов вашего отношения, прокрутите вниз до раздела 4.3.3:
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference
вы могли бы использовать
group_by
. Например, у меня есть корзина для покупок в фотогалерее, для которой я хочу, чтобы элементы заказа были отсортированы по фотографии (каждая фотография может быть заказана несколько раз и в разных размерах). Затем он возвращает хэш с продуктом (фото) в качестве ключа и каждый раз, когда он был заказан, может быть указан в контексте фотографии (или нет). Используя этот метод, вы можете фактически вывести историю заказов для каждого данного продукта. Не уверен, что это полезно для вас в этом контексте, но я нашел его весьма полезным. Вот кодOrdersController#show @order = Order.find(params[:id]) @order_items_by_photo = @order.order_items.group_by(&:photo)
@order_items_by_photo
тогда выглядит примерно так:=> {#<Photo id: 128>=>[#<OrderItem id: 2, photo_id: 128>, #<OrderItem id: 19, photo_id: 128>]
так что вы могли бы сделать что-то вроде:
@orders_by_product = @user.orders.group_by(&:product)
затем, когда вы получите это в вашем представлении, просто пройдите через что-то вроде этого:
- for product, orders in @user.orders_by_product - "#{product.name}: #{orders.size}" - for order in orders - output_order_details
таким образом, вы избегаете проблемы, наблюдаемой при возврате только одного продукта, так как вы всегда знаете, что он вернет хэш с продуктом в качестве ключа и массива ваших заказов.
это может быть излишним для того, что вы пытаетесь сделать, но это дает вам некоторые хорошие варианты (т. е. даты заказаны и т. д.) для работы с в дополнение к количеству.