Created
May 22, 2023 14:41
-
-
Save MadBomber/620d8c10f0e6b6a9ad449774c4ee64ee to your computer and use it in GitHub Desktop.
Auto-connection switching between read and write database
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/models/application_record.rb | |
class ApplicationRecord < ActiveRecord::Base | |
self.abstract_class = true | |
# When true, the database automatically switches connections | |
@@auto_switch_connection = true | |
# returns the name of the read replica if one is defined in database.yml, otherwise returns :primary | |
def self.reading_db | |
db_configs = ApplicationRecord.configurations.configs_for(env_name: Rails.env, include_replicas: true) | |
db_configs.find(&:replica?)&.name&.to_sym || :primary | |
end | |
connects_to database: { | |
writing: :primary, | |
reading: ApplicationRecord.reading_db | |
} | |
before_save :switch_to_primary_database | |
before_destroy :switch_to_primary_database | |
after_commit :switch_to_read_replica | |
after_rollback :switch_to_read_replica | |
# These cannot be private if we want to call them | |
# from inside a sidekiq worker or rails console. | |
# private | |
def switch_to_primary_database(switch_connection=nil) | |
ApplicationRecord.switch_to_primary_database(switch_connection) | |
end | |
def self.switch_to_primary_database(switch_connection=nil) | |
unless switch_connection.nil? | |
self.auto_switch_connection = switch_connection | |
ApplicationRecord.switch_to :writing | |
return | |
end | |
ApplicationRecord.switch_to(:writing) if ApplicationRecord.auto_switch_connection? | |
end | |
def switch_to_read_replica(switch_connection=nil) | |
ApplicationRecord.switch_to_read_replica(switch_connection) | |
end | |
def self.switch_to_read_replica(switch_connection=nil) | |
unless switch_connection.nil? | |
self.auto_switch_connection = switch_connection | |
ApplicationRecord.switch_to :reading | |
return | |
end | |
ApplicationRecord.switch_to(:reading) if ApplicationRecord.auto_switch_connection? | |
end | |
def self.switch_to(role) | |
unless [:reading, :writing].include? role | |
raise BadParameterError, "database rple is incorrect: #{role}" | |
end | |
ActiveRecord::Base.default_role = role | |
end | |
def self.auto_switch_connection? | |
!!@@auto_switch_connection | |
end | |
def self.auto_switch_connection=(a_boolean) | |
@@auto_switch_connection = a_boolean | |
end | |
def self.db_role | |
ActiveRecord::Base.default_role | |
end | |
def self.db_name | |
ActiveRecord::Base.connection.current_database | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When implementing this and adding the read only line in my application:
config.active_record.default_role = :reading
I am unable to run migrations. Any idea how to get migrations to run with a writer role?