mahemoff
mahemoff

Reputation: 46389

A callback for ActiveRecord database connections?

Is there any way to hook into ActiveRecord connection creation? I want to run some code whenever a connection has just been created.

I feel like it might be a way to set a MySQL variable on the connection, since "variables" in database.yml doesn't seem to work for me. (How to turn off MySQL strict mode in Rails)

Upvotes: 11

Views: 2690

Answers (3)

wondersz1
wondersz1

Reputation: 905

Just to add to the accepted solution, if you need to fire a database query from within the callback, you can do so in the following way:

ActiveRecord::ConnectionAdapters::AbstractAdapter.set_callback :checkout, :before, ->(conn) {
    res = conn.execute('SELECT COUNT(*) from table_name')
    puts "res is #{res.each { |tuple| puts tuple.inspect}}"
}

Note: since callback is defined on ActiveRecord::ConnectionAdapters::AbstractAdapter, this should be executed before checking out connection for ANY database type

As @Envek pointed out in comment to the accepted answer, you should not really use ActiveRecord models since you risk running into endless recursion. Also (also noted by @Envek) keep in mind that the callback will be fired on each connection checkout with pooled connections, not just once.

Finally, the chances are, you want to use this from Rails. If so, you can place this code in a file under config/initializers folder. Then it would be run on application startup. Useful for cases where you want to add logic to how database connection is established, especially if precise action depends on results of a specific query.

Upvotes: 1

Envek
Envek

Reputation: 4714

Also, if you need to configure your model after connection has been made and column information was retrieved, you can redefine load_schema! class method in model.

See: https://github.com/rails/rails/pull/31681#issuecomment-357113030

Upvotes: 2

Vladimir
Vladimir

Reputation: 191

The ConnectionAdapter defines two callbacks :checkout (connect) and :checkin (disconnect). You can use it for specific adapter as

ActiveRecord::ConnectionAdapters::MysqlAdapter.set_callback :checkout, :after do
  raw_connection.set_your_variables ...
end

Or you can use ActiveRecord::Base.connection.class for whatever adapter is currently declared in database.yml

Upvotes: 12

Related Questions