web-dev-qa-db-fra.com

Comment puis-je commander un has_many par association dans Ruby on Rails?

É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?

58
rswolff

É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
69
Daniel

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.

37
Martin T.

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 ]
12
denis.peplin

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

7
Antony Sastre

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
6
edx

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.

4
Ricardo Emerson

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.

2
Yogzzz

has_many: users, -> {order (: last_name,: first_name)},: through =>: assignments, source: 'user'

0
user223697