Rails ActiveRecord Scope, который является противоположностью другой области, или пользователи, у которых отсутствует свойство

У меня есть модель для user.rb, в которой я определяю область для admins, то есть пользователей, которые имеют роль администратора через таблицу разрешений.

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

Прицел работает так:

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

Я также хотел бы создать область действия под названием non-admins или что-то в этом роде, что касается всех пользователей, которые НЕ имеют роли администратора.

Как это сделать проще всего?


person isthmuses    schedule 18.01.2013    source источник


Ответы (2)


Простой способ, который неэффективен для многих пользователей:

admin_user_ids  = User.admins.map(&:id)
non_admin_users = User.all.reject { |u| admin_user_ids.include?(u.id) }
person Kris    schedule 19.05.2013
comment
Более быстрый способ первой строки - это сделать 'admin_user_ids = User.admins.pluck (: id)' - person mylescc; 13.07.2015

Если вы хотите получить инвертированный SQL-запрос, вам придется сделать это вручную. Встроенного решения ActiveRecord нет.

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

Если областей много или они сложные, рассмотрите возможность исключения их по идентификатору:

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))

В зависимости от количества строк и сложности исходного запроса это может быть медленнее или быстрее, чем предыдущий способ.

person Simon Perepelitsa    schedule 22.05.2013
comment
Что касается ваших решений для области видимости, у меня проблема в том, что когда я выполняю соединение и слияние, он будет учитывать только те объекты, для которых созданы связанные объекты. В моем случае я не имею дело с User + Permission. Поэтому мне нужно вернуть набор для всех объектов со связанными объектами со свойством false и для всех объектов без связанных. И твой путь мне не подходит - person miguelfg; 22.10.2015