Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails ActiveRecord Scope that is the "opposite" of another scope, or is users that "lack" a property

I have a model for user.rb, in which I define a scope for admins, which is users that have the role of admin through a permissions table.

has_many :permissions
has_many :roles, :through => :permissions

The scope works like this:

scope :admins, joins(:permissions).merge(Permission.admin_permissions)

I'd also like to make a scope called non-admins or something like that, which is all users that do NOT have the admin role.

What's the easiest way to do this?

like image 845
isthmuses Avatar asked Jan 18 '13 19:01

isthmuses


People also ask

What is an ActiveRecord scope?

Scopes are used to assign complex ActiveRecord queries into customized methods using Ruby on Rails. Inside your models, you can define a scope as a new method that returns a lambda function for calling queries you're probably used to using inside your controllers.

What is ActiveRecord in Ruby on Rails?

1 What is Active Record? Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.

How does Scope work in Rails?

Scopes are custom queries that you define inside your Rails models with the scope method. Every scope takes two arguments: A name, which you use to call this scope in your code. A lambda, which implements the query.

What does ActiveRecord where return?

Returns a new relation, which is the result of filtering the current relation according to the conditions in the arguments.


1 Answers

If you want to have an inverted SQL query, you will have to do it yourself manually. There is no built-in ActiveRecord solution.

scope :admins, joins(:permissions).merge(Permission.where("permissions.admin = true"))
scope :non_admins, joins(:permissions).merge(Permission.where("permissions.admin = false"))

If there are a lot of scopes or they are complex, consider excluding them by id:

User.where("id not in (?)", User.admins.pluck(:id))

# or if you are already using admin records
admins = User.admins
User.where("id not in (?)", admins.map(&:id))

Depending on number of rows and complexity of the original query, this could be slower or faster than the previous way.

like image 91
Simon Perepelitsa Avatar answered Nov 07 '22 23:11

Simon Perepelitsa