68 votes

Rails ActiveRecord : Trouver tous les utilisateurs sauf l'utilisateur actuel

J'ai l'impression que cela devrait être très simple mais mon cerveau est en train de court-circuiter sur ce point. Si j'ai un objet représentant l'utilisateur actuel, et que je veux interroger tous les utilisateurs sauf l'utilisateur actuel, comment puis-je le faire, en tenant compte du fait que l'utilisateur actuel peut parfois être nil ?

C'est ce que je fais en ce moment :

def index
  @users = User.all
  @users.delete current_user
end

Ce que je n'aime pas, c'est que je fais du post-traitement sur le résultat de la requête. En plus de me sentir un peu mal, je ne pense pas que cela fonctionnera bien si je convertis la requête pour être exécutée avec will_paginate . Avez-vous des suggestions sur la façon de faire cela avec une requête ? Merci.

2 votes

À mon avis, lorsque j'interroge quelque chose, je dois laisser la partie de mon application optimisée pour l'interrogation s'en charger : la base de données. Donc, post-traiter les résultats d'une requête pour les filtrer davantage, à mon avis, c'est placer la logique au mauvais endroit.

165voto

Mohamad Points 8497

Il est possible de faire ce qui suit dans Rails 4 et plus :

User.where.not(id: id)

Vous pouvez l'emballer dans un joli scope.

scope :all_except, ->(user) { where.not(id: user) }
@users = User.all_except(current_user)

Ou utilisez une méthode de classe si vous préférez :

def self.all_except(user)
  where.not(id: user)
end

Les deux méthodes renverront un objet de relation AR. Cela signifie que vous pouvez enchaîner les appels de méthodes :

@users = User.all_except(current_user).paginate

Vous pouvez exclure un nombre quelconque d'utilisateurs car where() accepte également un tableau.

@users = User.all_except([1,2,3])

Par exemple :

@users = User.all_except(User.unverified)

Et même par le biais d'autres associations :

class Post < ActiveRecord::Base
  has_many :comments
  has_many :commenters, -> { uniq }, through: :comments
end

@commenters = @post.commenters.all_except(@post.author)

Voir where.not() dans le Docs API .

1 votes

Le nombre de votes positifs finit-il par prendre le pas sur une réponse acceptée ?

0 votes

@wurde non :D - mais elle sera affichée, afin que les gens puissent voir les réponses que les utilisateurs apprécient le plus.

0 votes

Il faudrait placer une bannière sur les réponses acceptées avec lesquelles la communauté n'est pas d'accord. De la même manière que le gouvernement exige des bannières sur les cartons de cigarettes.

32voto

jdl Points 12272
@users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id]))

0 votes

Merci pour la suggestion de named_scope. Elle a permis de nettoyer un peu le contrôleur et de le rendre moins laid lors de la "mise à niveau" vers will_paginate. Merci encore.

16voto

GhandaL Points 141

Vous pouvez également créer named_scope, par exemple dans votre modèle :

named_scope :without_user, lambda{|user| user ? {:conditions => ["id != ?", user.id]} : {} }

et en contrôleur :

def index
  @users = User.without_user(current_user).paginate
end

Cette portée retournera tous les utilisateurs si elle est appelée avec nil et tous les utilisateurs sauf ceux donnés en paramètre dans les autres cas. L'avantage de cette solution est que vous êtes libre de chaîner cet appel avec d'autres scopes nommés ou la méthode will_paginate paginate.

0 votes

C'est la meilleure réponse. Gardez les données dans les scopes aussi longtemps que possible. De plus, c'est ainsi que la plupart des requêtes fonctionneront dans Rails 3 avec Arel.

1 votes

Utiliser les méthodes de la classe au lieu de la lambda du scope avec les paramètres

7voto

Harish Shetty Points 38877

Voici une version plus courte :

User.all :conditions => (current_user ? ["id != ?", current_user.id] : [])

0 votes

J'ai pris la réponse de l'utilisateur jdl, son commentaire sur les scopes nommés, et votre raffinement et je suis maintenant heureux. Le contrôleur est assez propre, bien que le named_scoped soit un peu laid. Après avoir ajouté will_paginate, voici ma requête : User.all_except(current_user).paginate(:page => params[:page])

6voto

Steve Bourne Points 641

Une remarque sur la réponse de GhandaL - au moins dans Rails 3, il vaut la peine de modifier en

scope :without_user, lambda{|user| user ? {:conditions => ["users.id != ?", user.id]} : {} }

(le changement principal ici est de passer de 'id != ...' à 'users.id !=...' ; également scope au lieu de named_scope pour Rails 3)

La version originale fonctionne bien lorsqu'on se contente de délimiter la table Utilisateurs. Lorsque l'on applique la portée à une association (par exemple team.members.without_user(current_user).... ), cette modification était nécessaire pour clarifier quelle table nous utilisons pour la comparaison des identifiants. J'ai vu une erreur SQL (en utilisant SQLite) sans cela.

Je m'excuse pour la réponse séparée... je n'ai pas encore la réputation de commenter directement la réponse de GhandaL.

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