Условно создайте новые записи для связи многих со многими в activerecords. - PullRequest
0 голосов
/ 18 декабря 2018

Я работаю над RoR проектом с ActiveRecord, и я довольно новичок в этих технологиях.

У меня есть две модели:

User.rb

class User < ApplicationRecord
...
has_and_belongs_to_many :roles
...

Role.rb

class Role < ApplicationRecord
...
has_and_belongs_to_many :users
...

Так что теперь я создаю новую роль:

Role.where(name: 'my_new_role').first_or_create!

и яхотите создать грабли, которые добавят эту роль для пользователей, которые уже имеют роль admin, и для всех других пользователей, которые НЕ имеют роли unfit_role.

Если бы я делал это с чистым SQLСкорее всего, я бы подготовил выбор для сбора всех идентификаторов пользователей, которые я хочу обновить, а затем выполнил бы другой запрос на обновление для всех собранных идентификаторов.

Однако я чувствую, что ActiveRecord имеет некоторые особенности, которые я пока не совсем понимаю, но я решил попробовать другой подход.

В настоящее время у меня есть этот код:

new_role = Role.where(name: :my_new_role).first

User.all.each do |entity|
  entity.roles << new_role if entity.has_role?('admin')
  entity.roles << new_role if !entity.has_role?('unfit_role')
end

И has_role - это простой вспомогательный метод, который выбирает все роли один раз и проверяет с помощью include?, находится ли данная роль в выбранном списке с ролями.

На основе 1-2 испытанийработает, кажется, что на самом деле это работает, но мне действительно не нравится реализация.Главным образом, я проверяю, есть ли у определенного пользователя (объекта) заданная роль.Я чувствую, что это довольно неэффективный способ выполнить относительно простую задачу, поэтому мне интересно, как можно реализовать это по-другому, чтобы это было быстрее.

1 Ответ

0 голосов
/ 18 декабря 2018

Вы можете использовать агрегатные функции Postgres , чтобы сделать запрос более эффективным:

new_role = Role.where(name: 'my_new_role').first!
admin_role = Role.where(name: 'admin').first!
unfit_role = Role.where(name: 'unfit_role').first!

User.joins(:roles).group(:id).having("bool_or(roles.id = #{admin_role.id}) or not bool_or(roles.id = #{unfit_role.id})").each do |entity|
  entity.roles << new_role
end
...