39 votes

Rails order by dans le modèle associé

J'ai deux modèles dans une relation has_many telle que Log has_many Items. Rails met alors en place des éléments tels que : some_log.items qui renvoie tous les éléments associés à some_log. Si je voulais ordonner ces éléments sur la base d'un champ différent dans le modèle Items, y a-t-il un moyen de le faire par une construction similaire, ou doit-on se décomposer en quelque chose comme :

Item.find_by_log_id(:all,some_log.id => "some_col DESC")

75voto

Greg Campbell Points 10321

Il existe plusieurs façons de procéder :

Si vous voulez que tous les appels à cette association soient ordonnés de cette façon, vous pouvez spécifier l'ordre lorsque vous créez l'association, comme suit :

class Log < ActiveRecord::Base
  has_many :items, :order => "some_col DESC"
end

Vous pourriez également le faire avec un named_scope, ce qui permettrait de spécifier facilement cette commande à chaque fois que l'on accède à Item :

class Item < ActiveRecord::Base
  named_scope :ordered, :order => "some_col DESC"
end

class Log < ActiveRecord::Base
  has_many :items
end

log.items # uses the default ordering
log.items.ordered # uses the "some_col DESC" ordering

Si vous souhaitez que les éléments soient toujours classés de la même manière par défaut, vous pouvez utiliser la méthode (nouvelle dans Rails 2.3) default_scope, comme suit :

class Item < ActiveRecord::Base
  default_scope :order => "some_col DESC"
end

12 votes

Depuis Rails 3.x, la syntaxe de named_scope est légèrement différente. Elle est maintenant appelée en utilisant "scope" au lieu de "named_scope", et utilise des fonctions pour définir la structure du scope. Par exemple : "scope :ordered, order("some_col DESC")".

14 votes

Dans Rails 4, il existe à nouveau une autre approche. La portée de l'association par défaut doit être spécifiée sous la forme d'une lambda comme has_many :items, ->{ order(:some_col).where(foo: 'bar') } et, de la même manière, les scopes nommés prennent maintenant un lambda scope :name_of_scope, ->{ where(foo: 'bar') } . La portée par défaut prend un bloc : default_scope: { where(foo: 'bar') }

0 votes

Superbe réponse. +1

16voto

lfender6445 Points 1361

rails 4.2.20 La syntaxe nécessite un appel avec un bloc :

class Item < ActiveRecord::Base
  default_scope { order('some_col DESC') }
end

Cela peut également être écrit avec une autre syntaxe :

default_scope { order(some_col: :desc) }

4voto

erik Points 3923

L'un ou l'autre devrait fonctionner :

Item.all(:conditions => {:log_id => some_log.id}, :order => "some_col DESC")
some_log.items.all(:order => "some_col DESC")

3voto

Sayuj Points 2134

Set default_scope dans votre classe de modèle

class Item < ActiveRecord::Base
  default_scope :order => "some_col DESC"
end

Cela va fonctionner

2 votes

@SsouLlesS Cela a répondu en 2011 quand il n'y avait pas de Rails 4.

0voto

ToTenMilan Points 118

ordre par relation directe has_many :model

est répondu aquí por Aaron

ordre par relation jointe has_many :modelable, through: :model

class Tournament
  has_many :games # this is a join table
  has_many :teams, through: :games

  # order by :name, assuming team has this column
  def teams
    super.order(:name)
  end
end

Tournament.first.teams # are returned ordered by name

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X