我正在和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次试运行,似乎实际上这是有效的,但我真的不喜欢实现。主要是我检查某个用户(实体)是否具有给定角色的方式。我觉得这是执行相对简单的任务的非常低效的方式,所以我想知道如何以不同的方式实现它,所以它更快。
您可以使用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