2010-04-20 23 views
53

Creo que esto debería ser muy simple, pero mi cerebro está cortocircuitando. Si tengo un objeto que representa al usuario actual y deseo consultar para todos los usuarios, excepto el usuario actual, ¿cómo puedo hacer esto, teniendo en cuenta que el usuario actual a veces puede ser nil?Rails ActiveRecord: Buscar todos los usuarios excepto el usuario actual

Esto es lo que estoy haciendo ahora:

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

Lo que no me gusta es que estoy haciendo post-procesamiento en el resultado de la consulta. Además de sentirme un poco mal, no creo que esto funcione bien si convierto la consulta para que se ejecute con will_paginate. ¿Alguna sugerencia de cómo hacer esto con una consulta? Gracias.

+1

En mi opinión cuando la consulta para algo que debería dejar que el parte de mi aplicación optimizada para consultar el manejador que: la base de datos. Por lo tanto, el procesamiento posterior de los resultados de una consulta para filtrarlo aún más, para mí, es colocar la lógica en el lugar equivocado. – SingleShot

Respuesta

119

Es posible hacer lo siguiente en los carriles 4:

User.where.not(id: id) 

se puede envolver en un ámbito agradable.

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

O utilice un método de clase, si lo prefiere:

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

Ambos métodos devolver un objeto relación con AR. Esto significa que puede método de la cadena de llamadas:

@users = User.all_except(current_user).paginate 

puede excluir cualquier número de usuarios, ya where() también acepta una matriz.

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

Por ejemplo:

@users = User.all_except(User.unverified) 

E incluso a través de otras asociaciones:

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

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

Ver where.not() en el API Docs.

+1

Entonces, ¿un recuento de votos positivos finalmente supera a una respuesta aceptada? – wurde

+0

@wurde no: D - pero estará ahí, para que la gente vea de qué respuesta obtienen el mayor valor para los usuarios. – Mohamad

+0

Debe colocar un banner en las respuestas aceptadas con el que la comunidad no está de acuerdo. Similar a cómo el gobierno requiere pancartas en los cartones de cigarrillos. – wurde

32
@users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id])) 
+0

Gracias por la sugerencia named_scope. Limpió un poco el controlador y lo hizo menos feo cuando se "actualiza" a will_paginate. Gracias de nuevo. – SingleShot

-5

Lo que está haciendo es eliminar el usuario_actual de la matriz @users. Esto no funcionará ya que no hay un método de eliminación para las matrices. Lo que es probable que desee hacer es esto

def index 
    @users = User.all 
    @users - [current_user] 
end 

Esto devolverá una copia de la matriz @users, pero con el objeto current_user eliminado (que estaba contenida en la matriz en el primer lugar.

Nota : Esto puede no funcionar si la resta de matriz se basa en coincidencias exactas de objetos y no en el contenido. Pero funcionó con cadenas cuando lo probé. Recuerde incluir current_user en [] para forzarlo a una matriz.

+0

Gracias por su respuesta. El ejemplo de código que envié funciona, de hecho, porque en realidad hay un método de eliminación en Array. Lamentablemente, su sugerencia no logra lo que estoy buscando. Gracias de nuevo. – SingleShot

+3

>> Array.new.methods.grep/delete/ => ["delete_at", "delete_if", "delete"] – user253455

+2

Esta respuesta también es incorrecta porque la vista de índice parcial usa la variable de instancia @users, que no ha cambiado por la operación '-'. No importa lo que devuelva el método 'index'. (Necesitaba usar el operador - = para cambiar @users en su lugar) – ndbroadbent

7

Aquí está una versión más corta:

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

Tomé la respuesta del usuario jdl, su comentario sobre los ámbitos nombrados, y su refinamiento, y ahora estoy contento. El controlador es bastante limpio, aunque named_scoped es un poco feo. Después de agregar will_paginate aquí está mi consulta: User.all_except (current_user) .paginate (: page => params [: page]) – SingleShot

+0

@SingleShot He editado la respuesta. –

+0

me queda bien. –

16

También puede crear named_scope, p. Ej. en su modelo:

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

y en el controlador:

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

Este alcance devolverá todos los usuarios cuando se le llama con nula y todos los usuarios excepto dada en parámetro en otro caso. La ventaja de esta solución es que puede encadenar esta llamada con otros ámbitos nombrados o con el método will_paginate de paginate.

+0

Esta es la mejor respuesta. Mantenga los datos en los alcances el mayor tiempo posible. Además, así es como la mayoría de las consultas funcionarán en Rails 3 con Arel. – Gdeglin

+0

Usa los métodos de clase en lugar del lambda de scope con los parámetros – Hauleth

6

Una nota sobre la respuesta de GhandaL - por lo menos en los carriles 3, vale la pena modificar a

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

(el cambio primordial en este caso es de a 'users.id = 'id = ...!'!. .. '; también ámbito en lugar de named_scope para Rails 3)

La versión original funciona bien cuando simplemente se analiza la tabla Usuarios. Al aplicar el alcance a una asociación (por ejemplo, team.members.without_user (current_user) ....), este cambio fue necesario para aclarar qué tabla estamos usando para la comparación de id. Vi un error de SQL (usando SQLite) sin él.

Disculpas por la respuesta separada ... todavía no tengo la reputación de comentar directamente sobre la respuesta de GhandaL.

2

solución muy sencilla que utiliza

@users = User.all.where("id != ?", current_user.id) 
0

Otra manera fácil que podía hacerlo:

@users = User.all.where("id NOT IN(?)", current_user.id) 
0

User.all.where ("? Id NO EN()", current_user.id) voluntad a través excepción método no definido donde por #<Array:0x0000000aef08f8>

User.where("id NOT IN (?)", current_user.id) 
0

una matriz sería más ayuda ful

arrayID [0] = 1

arrayID [1] = 3

User.where.not (id: arrayID)

Cuestiones relacionadas