有条件地为activerecords中的多对多关系创建新记录

问题描述 投票:0回答:1

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

ruby-on-rails rails-activerecord
1个回答
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
© www.soinside.com 2019 - 2024. All rights reserved.