Ruby on Rails: como faço para classificar com duas colunas usando ActiveRecord?

91

Quero classificar por duas colunas, uma é DateTime ( updated_at) e a outra é decimal (preço)

Gostaria de poder classificar primeiro por updated_at e, em seguida, se vários itens ocorrerem no mesmo dia, classificar por Preço.

NullVoxPopuli
fonte

Respostas:

64

Supondo que você esteja usando MySQL,

Model.all(:order => 'DATE(updated_at), price')

Observe a distinção entre as outras respostas. A updated_atcoluna será um carimbo de data / hora completo, portanto, se você deseja classificar com base no dia em que foi atualizado, você precisa usar uma função para obter apenas a parte da data do carimbo de data / hora. Em MySQL, é isso DATE().

Daniel Vandersluis
fonte
7
Para impedir que as junções sejam interrompidas aleatoriamente com mensagens de "coluna ambígua", você deve usar a seguinte versão mais robusta: :order => ["DATE(#{table_name}.updated_at)", :price](Observe que :priceé um símbolo.)
Jo Liss
Eu tive que escapar da minha coluna de pedidos orderassim:Model.all(:order => "day asc, `order` asc")
conceder
147

No Rails 4, você pode fazer algo semelhante a:

Model.order(foo: :asc, bar: :desc)

fooe barsão colunas no banco de dados.

Christian Fazzini
fonte
1
Rails 4 é o maior.
Darth Egregious de
56
Thing.find(:all, :order => "updated_at desc, price asc")

vai fazer o truque.

Atualizar:

Thing.all.order("updated_at DESC, price ASC")

é o caminho a seguir do Rails 3. (Obrigado @cpursley )

Erik Escobedo
fonte
4
Obrigado @Erik - eu sei que esta resposta é antiga, então aqui está o meu aviso para aqueles que a vêem agora: Este método foi descontinuado a partir do Rails 3.2. Em vez disso, use Thing.all =)
Abdo
Correto, funcionou bem para mim: Thing.all.order("updated_at DESC, price ASC")
cpursley de
1
Sua atualização foi útil para mim quando eu precisava para minúsculas os valores ordenados: Thing.order("LOWER(name), number").
Nick
36

A interface de consulta do Active Record permite que você especifique quantos atributos desejar para ordenar sua consulta:

models = Model.order(:date, :hour, price: :desc)

ou se você quiser ser mais específico (obrigado @ zw963 ):

models = Model.order(price: :desc, date: :desc, price: :asc) 

Bônus: após a primeira consulta, você pode encadear outras consultas:

models = models.where('date >= :date', date: Time.current.to_date)
golfadas
fonte
Sei que esta é uma postagem antiga, mas pessoalmente mudaria modelpara modelspara que uma pessoa soubesse que está plural. Apenas uma sugestão.
Tass
1
Acho que deveria editar um exemplo mais especial: por exemplo, models = Model.order ({price:: desc}, {date:: desc}, {price: asc})
zw963
se alguém colou isso e viu um erro de método indefinido, há um pequeno erro de digitação aqui. Deve ser em :ascvez de asc:Model.order({price: :desc}, {date: :desc}, {price: :asc})
nayiaw
18

Na verdade, existem muitas maneiras de fazer isso usando o Active Record. Um que não foi mencionado acima seria (em vários formatos, todos válidos):

Model.order(foo: :asc).order(:bar => :desc).order(:etc)

Talvez seja mais prolixo, mas pessoalmente acho mais fácil de gerenciar. O SQL é produzido em apenas uma etapa:

SELECT "models".* FROM "models" ORDER BY "models"."etc" ASC, "models"."bar" DESC, "models"."foo" ASC

Assim, para a pergunta original:

Model.order(:updated_at).order(:price)

Você não precisa declarar o tipo de dados, ActiveRecord faz isso sem problemas, e o mesmo acontece com o seu DB Engine

Ruby Racer
fonte
Isso funciona muito bem ao usar duas colunas de duas tabelas diferentes como: Member.includes (: voter) .order ("town_club asc"). Order ("voters.last_name asc")
bkunzi01
1
O SQL que você postou corresponde Model.order(foo: :asc).order(:bar => :desc).order(:etc)? A ordem das cláusulas de ordem no SQL é o oposto do que obtenho quando executo .to_sqlisso.
Qaz
1
@Qaz isso foi há muito tempo. Acho que provavelmente preciso corrigir este, nunca tinha percebido. Vou verificar mais tarde. Obrigado.
Ruby Racer
2
Model.all(:order => 'updated_at, price')
robertokl
fonte
0

Nada disso funcionou para mim! Depois de exatamente 2 dias procurando em cima e embaixo na internet, encontrei uma solução !!

digamos que você tenha muitas colunas na tabela de produtos, incluindo: special_price e msrp. Estas são as duas colunas com as quais estamos tentando classificar.

Ok, primeiro em seu modelo, adicione esta linha:

named_scope :sorted_by_special_price_asc_msrp_asc, { :order => 'special_price asc,msrp asc' }

Em segundo lugar, no Controlador de Produto, adicione onde você precisa realizar a pesquisa:

@search = Product.sorted_by_special_price_asc_msrp_asc.search(search_params)
Max Alexander Hanna
fonte