Estou me perguntando qual é a melhor maneira de exibir registros exclusivos de um has_many, por meio de relacionamento no Rails3.
Tenho três modelos:
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
Digamos que eu queira listar todos os produtos que um cliente pediu em sua página do programa.
Eles podem ter pedido alguns produtos várias vezes, então estou usando counter_cache para exibir em ordem decrescente de classificação, com base no número de pedidos.
Mas, se eles solicitaram um produto várias vezes, preciso garantir que cada produto seja listado apenas uma vez.
@products = @user.products.ranked(:limit => 10).uniq!
funciona quando há vários registros de pedido para um produto, mas gera um erro se um produto foi pedido apenas uma vez. (classificado é uma função de classificação personalizada definida em outro lugar)
Outra alternativa é:
@products = @user.products.ranked(:limit => 10, :select => "DISTINCT(ID)")
Não tenho certeza de estar na abordagem certa aqui.
Alguém mais abordou isso? Quais problemas você encontrou? Onde posso encontrar mais informações sobre a diferença entre .unique! e DISTINTO ()?
Qual a melhor forma de gerar uma lista de registros únicos através de um has_many, através de relacionamento?
obrigado
fonte
has_many :products, :through => :orders, :uniq => true
está obsoleto. Em vez disso, você deve escrever agorahas_many :products, -> { uniq }, through: :orders
.DISTINCT
eORDER BY
, você sempre pode usarhas_many :products, -> { unscope(:order).distinct }, through: :orders
has_many :subscribed_locations, -> { unscope(:order).select("DISTINCT ON (locations.id) locations.*") },through: :people_publication_subscription_locations, class_name: 'Location', source: :location
contráriorails ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: could not identify an equality operator for type json
Note que
uniq: true
foi removido das opções válidas parahas_many
Rails 4.No Rails 4 você deve fornecer um escopo para configurar este tipo de comportamento. Os escopos podem ser fornecidos por meio de lambdas, assim:
O guia do rails cobre esta e outras maneiras de usar escopos para filtrar as consultas de sua relação, role para baixo até a seção 4.3.3:
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference
fonte
undefined method 'except' for #<Array...
e foi porque usei no.uniq
lugar de.distinct
Você poderia usar
group_by
. Por exemplo, tenho um carrinho de compras de galeria de fotos para o qual desejo que os itens sejam classificados de acordo com a foto (cada foto pode ser pedida várias vezes e em impressões de tamanhos diferentes). Em seguida, retorna um hash com o produto (foto) como a chave e cada vez que ele foi pedido pode ser listado no contexto da foto (ou não). Usando essa técnica, você pode gerar um histórico de pedidos para cada produto. Não tenho certeza se isso é útil para você neste contexto, mas achei bastante útil. Aqui está o código@order_items_by_photo
então se parece com isto:Então você pode fazer algo como:
Então, quando você conseguir isso em sua visão, apenas percorra algo assim:
Desta forma, você evita o problema de devolver apenas um produto, pois sempre sabe que ele retornará um hash com um produto como chave e um array de seus pedidos.
Pode ser um exagero para o que você está tentando fazer, mas oferece algumas opções interessantes (ou seja, datas solicitadas, etc.) para trabalhar além da quantidade.
fonte
No Rails 6 eu fiz isso funcionar perfeitamente:
Não consegui fazer nenhuma das outras respostas funcionar.
fonte