我想将公司的数据库从应用程序级审核转移到数据库级审核。我将使用此处详细介绍的91audit触发器:https://github.com/2ndQuadrant/audit-trigger/blob/master/audit.sql
DB级审核的问题在于它实际上并没有记录当前用户,而是记录了postgresql用户。
应用程序级别审核的缺点是我必须通过Web应用程序运行每笔交易,以便对更改进行审核(如果我在同一个数据库中有多个应用程序,则无法很好地工作>
我在这里找到了一个非常有趣的解决方案:http://schinckel.net/2014/06/01/in-database-audit-trail/
该解决方案依赖于在每次交易开始时在临时表上更新/插入一行。
现在
为了使此功能对我有用,我想在任何保存,更新,销毁或删除调用上添加一个钩子以更新此临时表。
我的问题是:
Rails 5.2+是否存在顶级transaction-start
钩子;最好是我可以在内部和初始化程序或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
答案 0 :(得分:0)
覆盖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