Ruby on Rails: comment trier avec deux colonnes en utilisant ActiveRecord?

91

Je veux trier par deux colonnes, l'une est un DateTime ( updated_at) et l'autre est un Decimal (Price)

Je voudrais pouvoir trier d'abord par updated_at, puis, si plusieurs éléments se produisent le même jour, trier par prix.

NullVoxPopuli
la source

Réponses:

64

En supposant que vous utilisez MySQL,

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

Notez la distinction avec les autres réponses. La updated_atcolonne sera un horodatage complet, donc si vous souhaitez trier en fonction du jour où elle a été mise à jour, vous devez utiliser une fonction pour obtenir uniquement la partie date à partir de l'horodatage. Dans MySQL, c'est DATE().

Daniel Vandersluis
la source
7
Pour empêcher les jointures de se rompre au hasard avec des messages de "colonne ambiguë", vous devez utiliser la version plus robuste suivante: :order => ["DATE(#{table_name}.updated_at)", :price](Notez que :pricec'est un symbole.)
Jo Liss
J'ai dû échapper à ma colonne de commande avec ordercomme ça:Model.all(:order => "day asc, `order` asc")
accorder
147

Dans Rails 4, vous pouvez faire quelque chose de similaire à:

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

fooet barsont des colonnes dans la base de données.

Christian Fazzini
la source
1
Rails 4 est le meilleur.
Darth Egregious
56
Thing.find(:all, :order => "updated_at desc, price asc")

fera l'affaire.

Mettre à jour:

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

est la voie à suivre pour Rails 3. (Merci @cpursley )

Erik Escobedo
la source
4
Merci @Erik - Je sais que cette réponse est ancienne, voici donc mon avertissement pour ceux qui la voient maintenant: Cette méthode est obsolète à partir de Rails 3.2. Utilisez Thing.all à la place =)
Abdo
Correct, cela a bien fonctionné pour moi: Thing.all.order("updated_at DESC, price ASC")
cpursley
1
Votre mise à jour a été utile pour moi quand je devais en minuscules les valeurs triées: Thing.order("LOWER(name), number").
Nick
36

Interface de requête d'enregistrement actif vous permet de spécifier autant d'attributs que vous souhaitez ordonner votre requête:

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

ou si vous voulez être plus précis (merci @ zw963 ):

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

Bonus: après la première requête, vous pouvez enchaîner d'autres requêtes:

models = models.where('date >= :date', date: Time.current.to_date)
golfadas
la source
Je sais que c'est un ancien poste, mais personnellement je change modelde modelssorte qu'une personne sache qu'il est pluralisé. Juste une suggestion.
Tass
1
Je pense que je devrais modifier un exemple plus spécialement: par exemple models = Model.order ({price:: desc}, {date:: desc}, {price: asc})
zw963
si quelqu'un a collé ceci et a vu une erreur de méthode non définie, il y a une petite faute de frappe ici. Il devrait être :ascau lieu de asc:Model.order({price: :desc}, {date: :desc}, {price: :asc})
nayiaw
18

En fait, il existe de nombreuses façons de le faire en utilisant Active Record. Celui qui n'a pas été mentionné ci-dessus serait (dans divers formats, tous valides):

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

C'est peut-être plus bavard, mais personnellement, je trouve que c'est plus facile à gérer. SQL est produit en une seule étape:

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

Ainsi, pour la question initiale:

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

Vous n'avez pas besoin de déclarer le type de données, ActiveRecord le fait facilement, tout comme votre DB Engine

Ruby Racer
la source
Cela fonctionne très bien lorsque vous utilisez deux colonnes de deux tables différentes telles que: Member.includes (: vote) .order ("town_club asc"). Order ("vectors.last_name asc")
bkunzi01
1
Le SQL que vous avez publié correspond-il Model.order(foo: :asc).order(:bar => :desc).order(:etc)? L'ordre des clauses d'ordre dans le SQL est le contraire de ce que j'obtiens quand je cours .to_sqldessus.
Qaz
1
@Qaz, c'est il y a longtemps. Je pense que j'ai probablement besoin de corriger celui-ci, je ne l'avais jamais remarqué. Je vérifierai plus tard. Merci.
Ruby Racer
2
Model.all(:order => 'updated_at, price')
robertokl
la source
0

Aucun de ceux-ci n'a fonctionné pour moi! Après exactement 2 jours de recherche de haut en bas sur Internet, j'ai trouvé une solution !!

disons que vous avez de nombreuses colonnes dans la table products, y compris: special_price et msrp. Ce sont les deux colonnes avec lesquelles nous essayons de trier.

D'accord, tout d'abord dans votre modèle, ajoutez cette ligne:

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

Deuxièmement, dans le contrôleur de produit, ajoutez où vous devez effectuer la recherche:

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