How to configure an ActiveRecord connection?

Hi all

I’m wondering if there is a sanctioned way in Rails to configure an ActiveRecord connection? Each connection adapter seems to do a bit of connection configuring, and I’d like to extend that.

I’m currently doing some class_eval hackery with alias_method, but ideally there’s a better way I don’t know of.

require "active_record/connection_adapters/sqlite3_adapter"

ActiveRecord::ConnectionAdapters::SQLite3Adapter.class_eval do
  alias_method :before_configure_connection, :configure_connection

  def configure_connection
    # Log SCHEMA statements because I want to know what's going on
    ActiveRecord::LogSubscriber::IGNORE_PAYLOAD_NAMES -= ["SCHEMA"]

    # Call the previous implementation of configure_connection
    before_configure_connection

    # Do some connection configuring
    # connection.foreign_keys = true # Already done by Rails in before_ via execute("PRAGMA...")
    @connection.journal_mode = 'wal' # default is 'delete'
    @connection.synchronous = 'normal' # default is 'full' (2)
    @connection.temp_store = 'memory' # default is 'default' (0)
    logger.info { "sqlite connection configured: foreign_keys = #{@connection.foreign_keys}, journal_mode = #{@connection.journal_mode}, synchronous = #{@connection.synchronous}, temp_store = #{@connection.temp_store}"}
  end
end

Thanks for any help!

Unrelated to your question but I would be careful with setting synchronous to something else than ‘full’. SQLite is OK for testing purposes and situations where you are sure that access is occurring from a single thread at a time but for any other use I would recommend using a different database. PostgreSQL for example.

Monkeying around with internals will never be sanctioned, and I would use extreme caution. This particular method didn’t appear in the codebase until 5.1, and in my experience ActiveRecord internals can undergo breaking structural changes between minor version bumps.

If you want to monkeypatch ActiveRecord internals safely (or at least, as safe as you can be), I recommend you do it like I have done and limit your patches to known minor versions.

Now that I have sufficiently warned you off from doing this, here’s how I would implement this:

module ConfigureConnection
  def configure_connection
    ActiveRecord::LogSubscriber::IGNORE_PAYLOAD_NAMES -= ["SCHEMA"]

    super

    @connection.journal_mode = 'wal'
    @connection.synchronous = 'normal'
    @connection.temp_store = 'memory'
    logger.info { "sqlite connection configured: foreign_keys = #{@connection.foreign_keys}, journal_mode = #{@connection.journal_mode}, synchronous = #{@connection.synchronous}, temp_store = #{@connection.temp_store}"}
  end
end

ActiveSupport.on_load(:active_record, run_once: true) do
  require "active_record/connection_adapters/sqlite3_adapter"
  ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend ConfigureConnection
end
1 Like

That’s why I am asking IF there’s a sanctioned way. Thank you for the recommendation, this looks better than the method alias. I guess I can secure this with a simple integration test, but an official way to configure a connection would be nice to have.

Thank you for the concern :slight_smile: With “normal” you lose a bit of durability, because there is no sync after a committed transaction, but according to Sqlite docs it’s cool with WAL mode.

The synchronous=NORMAL setting is a good choice for most applications running in WAL mode.

I am using Sqlite in production, for my use case it’s completely sufficient.