我有一些初始化函数,用于在PostgreSQL中设置DB服务器端(即不是rails)的审计日志记录。在将数据插入或更新任何审计表之前,至少要发出 (设置当前用户),否则整个查询将会失败。
每次在代码中运行任何保存操作之前,我都可以很容易地调用它们,但DRY让我觉得我应该尽可能少地重复代码,特别是因为这与数据库不可知论的理想大相径庭。目前我正在尝试覆盖初始化程序中的ActiveRecord :: Base.establish_connection以进行设置,以便在我自动连接时立即运行查询,但它不会像我期望的那样运行。以下是初始化程序中的代码:
class ActiveRecord::Base # extend the class methods, not the instance methods class << self alias :old_establish_connection :establish_connection # hide the default def establish_connection(*args) ret = old_establish_connection(*args) # call the default # set up necessary session variables for audit logging # call these after calling default, to make sure conn is established 1st db = self.class.connection db.execute("SELECT SV.set('current_user', 'test@localhost')") db.execute("SELECT SV.set('audit_notes', NULL)") # end "empty variable" err ret # return the default's original value end end end puts "Loaded custom establish_connection into ActiveRecord::Base"
sycobuny:~/rails$ ruby script/server => Booting WEBrick => Rails 2.3.5 application starting on http://0.0.0.0:3000 Loaded custom establish_connection into ActiveRecord::Base
这不会给我任何错误,不幸的是我无法检查内部的方法(我使用的是ActiveRecord :: Base.method(:establish_connection)),但显然每次都会创建一个新的Method对象它被调用,这看似毫无价值,因为我无法检查object_id是否有任何有价值的信息,我也无法反转编译)。
但是,似乎永远不会调用代码,因为任何尝试对数据库对象运行保存或更新都会失败,正如我之前预测的那样。如果这不是在连接数据库时立即执行代码的正确方法,那么是什么?
答案 0 :(得分:3)
Rails使用连接池,所以最好的办法是使用alias_method_chain for ActiveRecord :: ConnectionAdapters :: ConnectionPool #new_connection
module ActiveRecord
Module ConnectionAdapters
class ConnectionPool
alias_method_chain :new_connection, :my_stuff
private
def new_connection_with_my_stuff
c = new_connection_without_my_stuff
# Do your stuff with
# c.exec(<your sql command>)
c
end
end
end
end
答案 1 :(得分:0)
您知道在建立数据库连接之前调用了初始化程序吗?
如果没有关于可能出错的权威信息,我会利用ActiveRecord的源代码在我的硬盘上。
深入了解基类并进行一些调试,以查看何时调用ActiveRecord的establish_connection相对于调用初始化程序的时间。或者只是打开额外的详细调试。
答案 2 :(得分:0)
在编写用于挂钩rails数据库调用和初始化的代码方面,您可能希望使用db-charmer中的代码作为模板。它演示了许多与ActiveRecord交互的有趣方式,其中一个可能会做你想要的。