Étant donné les modèles AR suivants, je voudrais trier les utilisateurs par ordre alphabétique par nom de famille lorsque l'on donne une poignée à une tâche:
#user
has_many :assignments
has_many :tasks, :through => :assignments
#assignment
belongs_to :task
belongs_to :user
#task
has_many :assignments
has_many :users, :through => :assignments
Je voudrais obtenir une tâche puis naviguer vers les utilisateurs qui lui sont affectés, et trier la liste des utilisateurs par ordre alphabétique.
Je continue de penser que je devrais pouvoir ajouter le :order
clause à has_many :users, :through => :assignments
comme ça:
#task.rb
has_many :assignments
has_many :users, :through => :assignments, :order => 'last_name, first_name'
cependant, cela ne fonctionne pas.
Comment trier les utilisateurs par last_name
quand on vous confie une tâche?
Étant donné que les arguments de condition sont obsolètes dans Rails 4, il convient d'utiliser des blocs de portée:
has_many :users, -> { order 'users.last_name, users.first_name' }, :through => :assignments
Version Rails 3.x:
has_many :users, :through => :assignments, :order => 'users.last_name, users.first_name'
MISE À JOUR: Cela ne fonctionne que dans Rails 3.x (peut-être avant cela aussi). Pour 4+, voir les autres réponses.
Le M.G.Palmer's
l'approche fonctionne bien, mais le nom de la table est impliqué. Il y a une meilleure façon de le faire:
has_many :users, :through => :assignments, :order => [ :last_name, :first_name ]
Est-ce que cela fonctionnerait pour vous?
# User.rb
class User < ActiveRecord::Base
default_scope :order => 'last_name ASC'
...
end
Vous pouvez définir d'autres étendues nommées lorsque le tri doit être différent.
http://ryandaigle.com/articles/2008/11/18/what-s-new-in-Edge-Rails-default-scoping
Cela fonctionne pour moi (Rails 4.2)
L'application d'un ordre sur la carte traversante n'est pas conservée, ce qui n'est pas suffisant pour ordonner les genres:
has_many :disk_genre_maps,
-> {order('disk_genre_map.sort_order')},
:inverse_of => :disk,
:dependent => :destroy,
:autosave => true
has_many :genres, # not sorted like disk_genre_maps
:through => :disk_genre_maps,
:source => :genre,
:autosave => true
Je remplace donc ceci par instance:
def genres # redefine genres per instance so that the ordering is preserved
self.disk_genre_maps.map{|dgm|dgm.genre}
end
Pour que cela fonctionne pour les affectations, cela devrait être quelque chose comme ça (non testé)
def genres= some_genres
self.disk_genre_maps = some_genres.map.with_index do |genre, index|
DiskGenreMap.new(disk:self, genre:genre, sort_order:index)
end
end
J'utilise Rails (5.0.0.1) et je pourrais faire le tri avec cette syntaxe dans mon groupe de modèles qui a de nombreux utilisateurs via group_users:
# Associations.
has_many :group_users
has_many :users, -> { order(:name) }, through: :group_users
Adaptez le code à votre besoin qui fonctionnera.
Vous pouvez également créer une nouvelle colonne 'sort_order' sur la table d'affectation et ajouter une étendue par défaut comme
default_scope { order('sort_order desc')}
à votre modèle d'affectations.
has_many: users, -> {order (: last_name,: first_name)},: through =>: assignments, source: 'user'