我正在与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!
并且我想创建一个rake任务,该任务将为已经拥有admin
角色的用户和所有其他没有unfit_role
角色的用户添加此角色。
如果我使用纯SQL
进行此操作,则很可能会执行一次选择以收集要更新的所有用户ID,然后对收集的所有ID执行另一个更新查询。
但是我觉得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次尝试运行,看来这实际上是可行的,但我真的不喜欢该实现。通常,我检查某个用户(实体)是否具有给定角色的方式。我觉得这是执行相对简单的任务的效率很低的方法,所以我想知道如何以其他方式实现它,从而更快。
答案 0 :(得分:0)
您可以使用Postgres aggregate functions来提高查询效率:
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