我遇到的情况是我尝试从特定数据库中删除角色列表,但该角色正在服务器上的多个数据库中使用。
根据the documentation for Dropping Roles,我已按照说明操作:
REASSIGN OWNED BY doomed_role TO successor_role;
DROP OWNED BY doomed_role;
-- repeat the above commands in each database of the cluster
DROP ROLE doomed_role;
文档还说明:
因为REASSIGN OWNED [和DROP OWNED]无法访问其他数据库中的对象,所以必须在包含该角色所拥有的对象的每个数据库中运行它。
正如预期的那样,当我运行上述命令时:
conn = ActiveRecord::Base.connection
conn.execute("REASSIGN OWNED BY viewer_role TO postgres")
conn.execute("DROP OWNED BY viewer_role")
conn.execute("DROP ROLE IF EXISTS viewer_role")
我收到错误消息:
ActiveRecord::StatementInvalid: PG::DependentObjectsStillExist:
ERROR: role "viewer_role" cannot be dropped because some objects depend on it
DETAIL:
35 objects in database inst2
35 objects in database inst3
35 objects in database inst4
在rails应用的上下文中,如何为所有数据库调用REASSIGN OWNED
和DROP OWNED
?
我的猜测是我将不得不连接到每个数据库。我找到了一个有效的解决方案:
module DBS
@@connections = {}
# get all databases
conn = ActiveRecord::Base.connection;
dbs = conn.select_values('SELECT datname FROM pg_database WHERE datistemplate = false')
# create a connection to each database - this will raise lots and lots of warnings
dbs.each do |db_name|
@@connections[db_name] ||=
begin
config = ActiveRecord::Base.connection_config
config = config.merge({database: db_name})
model = Class.new(ActiveRecord::Base)
self.const_set("#{db_name.classify}", model) # This is needed as rails raises an error if the class does not have a name :@
model.establish_connection(config)
model.connection
end
end
def self.connections
@@connections
end
end
roles.each do |role_name|
DBS.connections.values.each do |conn|
conn.execute("REASSIGN OWNED BY #{role_name} TO postgres")
conn.execute("DROP OWNED BY #{role_name}")
end
ActiveRecord::Base.connection.execute("DROP ROLE IF EXISTS #{role_name}")
end
但是,仅使用已经建立的ActiveRecord::Base.connection
是否可以做同样的事情?