ruby-on-rails - Rails 事务启动钩子
问题描述
我想将我公司的数据库从应用程序级审计转移到数据库级审计。我将使用此处详述的 91audit 触发器:https ://github.com/2ndQuadrant/audit-trigger/blob/master/audit.sql
数据库级别审计的问题在于它实际上并没有记录当前用户,它记录的是 postgresql 用户。
应用程序级审计的缺点是我必须通过网络应用程序运行每个事务才能对更改进行审计(如果我在同一个数据库上有多个应用程序,则效果不佳)
我在这里找到了一个非常有趣的解决方案:http: //schinckel.net/2014/06/01/in-database-audit-trail/
该解决方案依赖于在每个事务开始时在临时表上更新/插入一行。
现在
为了让这对我有用,我想在 rails 添加一个钩子,以便在任何保存、更新、销毁或删除调用时更新这个临时表。
我的问题是:
transaction-start
Rails 5.2+是否存在顶级钩子?最好是我可以在内部和初始化程序中设置的东西,或者ApplicationRecord
?
我的第一个想法是添加一个初始化程序,但我不知道我会加入什么
我的备用计划是覆盖ApplicationRecord.transaction
class ApplicationRecord < ActiveRecord::Base
def self.transaction(*args)
super(*args) do
if Current.user
ActiveRecord::Base.connection.execute(%Q(
CREATE TEMP TABLE IF NOT EXISTS
"_app_user" (user_id integer, ip_address inet);
UPDATE
_app_user
SET
user_id=#{Current.user.id},
ip_address='#{Current.ip_address}';
INSERT INTO
_app_user (user_id, ip_address)
SELECT
#{Current.user.id}, '#{Current.ip_address}'
WHERE NOT EXISTS (SELECT * FROM _app_user);
))
end
yield
end
end
end
解决方案
覆盖 ActiveRecord.transaction 似乎工作得很好
class ApplicationRecord < ActiveRecord::Base
def self.transaction(*args)
super(*args) do
if Current.user
ip = Current.ip_address ? "'#{Current.ip_address}'" : 'NULL'
ActiveRecord::Base.connection.execute <<-SQL
CREATE TEMP TABLE IF NOT EXISTS
"_app_user" (user_id integer, user_type text, ip_address inet);
UPDATE
_app_user
SET
user_id=#{Current.user.id},
user_type='#{Current.user.class.to_s}',
ip_address=#{ip};
INSERT INTO
_app_user (user_id, user_type, ip_address)
SELECT
#{Current.user.id},
'#{Current.user.class.to_s}',
#{ip}
WHERE NOT EXISTS (SELECT * FROM _app_user);
SQL
end
yield
end
end
end
推荐阅读
- c++ - 写入文件和标准输出,std::cout 未显示全部
- performance - 如何使用 FormApp...getResponses() 减少脚本执行时间?
- c# - 尝试使用 'dbcontext.tablename.local' 获取本地列表会引发错误
- handlebars.js - Handlebars - 在带有@root 的条件语句中访问“this”
- asp.net-core - 获取 ASP .NET Core 3.1 / Kestrel 中的连接数
- python - 优化归并排序
- c# - 工作系统,团结 | 包含不同类型的结构的本机数组。错误 InvalidOperationException
- python - 什么是根据另一列中的值填充列的更有效方法
- word2vec - In embedding using word2vec 中的表达式“binary=True”
- php - register_shutdown_function 未按预期顺序调用