问题
I feel this should be very simple but my brain is short-circuiting on it. If I have an object representing the current user, and want to query for all users except the current user, how can I do this, taking into account that the current user can sometimes be nil?
This is what I am doing right now:
def index
@users = User.all
@users.delete current_user
end
What I don't like is that I am doing post-processing on the query result. Besides feeling a little wrong, I don't think this will work nicely if I convert the query over to be run with will_paginate. Any suggestions for how to do this with a query? Thanks.
回答1:
It is possible to do the following in Rails 4:
User.where.not(id: id)
You can wrap it in a nice scope.
scope :all_except, ->(user) { where.not(id: user) }
@users = User.all_except(current_user)
Or use a class method if you prefer:
def self.all_except(user)
where.not(id: user)
end
Both methods will return an AR relation object. This means you can chain method calls:
@users = User.all_except(current_user).paginate
You can exclude any number of users because where() also accepts an array.
@users = User.all_except([1,2,3])
For example:
@users = User.all_except(User.unverified)
And even through other associations:
class Post < ActiveRecord::Base
has_many :comments
has_many :commenters, -> { uniq }, through: :comments
end
@commenters = @post.commenters.all_except(@post.author)
See where.not() in the API Docs.
回答2:
@users = (current_user.blank? ? User.all : User.find(:all, :conditions => ["id != ?", current_user.id]))
回答3:
You can also create named_scope, e.g. in your model:
named_scope :without_user, lambda{|user| user ? {:conditions => ["id != ?", user.id]} : {} }
and in controller:
def index
@users = User.without_user(current_user).paginate
end
This scope will return all users when called with nil and all users except given in param in other case. The advantage of this solution is that you are free to chain this call with other named scopes or will_paginate paginate method.
回答4:
Here is a shorter version:
User.all :conditions => (current_user ? ["id != ?", current_user.id] : [])
回答5:
One note on GhandaL's answer - at least in Rails 3, it's worth modifying to
scope :without_user, lambda{|user| user ? {:conditions => ["users.id != ?", user.id]} : {} }
(the primary change here is from 'id != ...' to 'users.id !=...'; also scope instead of named_scope for Rails 3)
The original version works fine when simply scoping the Users table. When applying the scope to an association (e.g. team.members.without_user(current_user).... ), this change was required to clarify which table we're using for the id comparison. I saw a SQL error (using SQLite) without it.
Apologies for the separate answer...i don't yet have the reputation to comment directly on GhandaL's answer.
回答6:
Very easy solution I used
@users = User.all.where("id != ?", current_user.id)
回答7:
User.all.where("id NOT IN(?)", current_user.id) will through exception
undefined method where for #<Array:0x0000000aef08f8>
User.where("id NOT IN (?)", current_user.id)
回答8:
Another easy way you could do it:
@users = User.all.where("id NOT IN(?)", current_user.id)
回答9:
an array would be more helpful
arrayID[0]=1
arrayID[1]=3
User.where.not(id: arrayID)
回答10:
User.where(:id.ne=> current_user.id)
回答11:
What you are doing is deleting the current_user from the @users Array. This won't work since there isn't a delete method for arrays. What you probably want to do is this
def index
@users = User.all
@users - [current_user]
end
This will return a copy of the @users array, but with the current_user object removed (it it was contained in the array in the first place.
Note: This may not work if array subtraction is based on exact matches of objects and not the content. But it worked with strings when I tried it. Remember to enclose current_user in [] to force it into an Array.
来源:https://stackoverflow.com/questions/2672744/rails-activerecord-find-all-users-except-current-user