модуль ActiveRecord::ConnectionHandling
Обработка подключений Active Record
Константы
- DEFAULT_ENV
- RAILS_ENV
Атрибуты
Общедоступные методы экземпляра
# File activerecord/lib/active_record/connection_handling.rb, line 258
def clear_query_caches_for_current_thread
connection_handler.each_connection_pool do |pool|
pool.clear_query_cache
end
end Очищает кэш запросов для всех подключений, связанных с текущей нитью.
# File activerecord/lib/active_record/connection_handling.rb, line 351 def connected? connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard) end
Возвращает true , если Active Record подключен.
# File activerecord/lib/active_record/connection_handling.rb, line 136
def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
if self != Base && !abstract_class
raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
end
if !connection_class? && !primary_class?
raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
end
unless role || shard
raise ArgumentError, "must provide a `shard` and/or `role`."
end
with_role_and_shard(role, shard, prevent_writes, &blk)
end Подключается к роли (например, записи, чтению или пользовательской роли) и/или фрагменту на время выполнения блока. По окончании блока подключение вернётся к исходной роли/фрагменту.
Если передана только роль, Active Record найдёт подключение, соответствующее запрошенной роли. Если запрошенная роль не установлена, будет выброшено исключение ActiveRecord::ConnectionNotEstablished.
ActiveRecord::Base.connected_to(role: :writing) do Dog.create! # creates dog using dog writing connection end ActiveRecord::Base.connected_to(role: :reading) do Dog.create! # throws exception because we're on a replica end
При переключении на фрагмент также необходимо указать роль. Если указан несуществующий фрагмент, будет выброшено исключение ActiveRecord::ConnectionNotEstablished.
Если переданы фрагмент и роль, Active Record сначала найдёт роль, а затем подключение по ключу фрагмента.
ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do Dog.first # finds first Dog record stored on the shard one replica end
# File activerecord/lib/active_record/connection_handling.rb, line 253 def connected_to?(role:, shard: ActiveRecord::Base.default_shard) current_role == role.to_sym && current_shard == shard.to_sym end
Возвращает true, если роль является текущей подключенной ролью и/или текущим подключенным фрагментом. Если фрагмент не указан, используется значение по умолчанию.
ActiveRecord::Base.connected_to(role: :writing) do ActiveRecord::Base.connected_to?(role: :writing) #=> true ActiveRecord::Base.connected_to?(role: :reading) #=> false end ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one) #=> true ActiveRecord::Base.connected_to?(role: :reading, shard: :default) #=> false ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one) #=> true end
# File activerecord/lib/active_record/connection_handling.rb, line 186
def connected_to_all_shards(role: nil, prevent_writes: false, &blk)
shard_keys.map do |shard|
connected_to(shard: shard, role: role, prevent_writes: prevent_writes, &blk)
end
end Передает блок методу connected_to для каждого shard , с которым настроено подключение модели (если таковые имеются), и возвращает результаты в массиве.
Можно дополнительно передать role и/или prevent_writes, которые будут переданы каждому вызову connected_to.
# File activerecord/lib/active_record/connection_handling.rb, line 165
def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
classes = classes.flatten
if self != Base || classes.include?(Base)
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
end
prevent_writes = true if role == ActiveRecord.reading_role
append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
yield
ensure
connected_to_stack.pop
end Подключает роль и/или фрагмент к указанным именам подключений. Дополнительно можно передать prevent_writes, чтобы заблокировать запись в подключение. reading автоматически установит prevent_writes в значение true.
connected_to_many - альтернатива глубоко вложенным connected_to блокам.
Использование:
ActiveRecord::Base.connected_to_many(AnimalsRecord, MealsRecord, role: :reading) do Dog.first # Read from animals replica Dinner.first # Read from meals replica Person.first # Read from primary writer end
# File activerecord/lib/active_record/connection_handling.rb, line 199 def connecting_to(role: default_role, shard: default_shard, prevent_writes: false) prevent_writes = true if role == ActiveRecord.reading_role append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self]) end
Использование указанного подключения.
Этот метод полезен для обеспечения использования определенного подключения. Например, при запуске консоли в режиме только для чтения.
Не рекомендуется использовать этот метод в запросе, так как он не передает управление блоку, как connected_to.
# File activerecord/lib/active_record/connection_handling.rb, line 274
def connection
pool = connection_pool
if pool.permanent_lease?
case ActiveRecord.permanent_connection_checkout
when :deprecated
ActiveRecord.deprecator.warn <<~MESSAGE
Called deprecated `ActiveRecord::Base.connection` method.
Either use `with_connection` or `lease_connection`.
MESSAGE
when :disallowed
raise ActiveRecordError, <<~MESSAGE
Called deprecated `ActiveRecord::Base.connection` method.
Either use `with_connection` or `lease_connection`.
MESSAGE
end
pool.lease_connection
else
pool.active_connection
end
end Устаревший метод. Используйте #with_connection или #lease_connection вместо него.
# File activerecord/lib/active_record/connection_handling.rb, line 334 def connection_db_config connection_pool.db_config end
Возвращает объект db_config из связанного подключения:
ActiveRecord::Base.connection_db_config
#<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
@name="primary", @config={pool: 5, timeout: 5000, database: "storage/development.sqlite3", adapter: "sqlite3"}> Используйте только для чтения.
# File activerecord/lib/active_record/connection_handling.rb, line 342 def connection_pool connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard, strict: true) end
# File activerecord/lib/active_record/connection_handling.rb, line 316
def connection_specification_name
if @connection_specification_name.nil?
return self == Base ? Base.name : superclass.connection_specification_name
end
@connection_specification_name
end Возвращает имя спецификации подключения из текущего класса или его родителя.
# File activerecord/lib/active_record/connection_handling.rb, line 81
def connects_to(database: {}, shards: {})
raise NotImplementedError, "`connects_to` can only be called on ActiveRecord::Base or abstract classes" unless self == Base || abstract_class?
if database.present? && shards.present?
raise ArgumentError, "`connects_to` can only accept a `database` or `shards` argument, but not both arguments."
end
connections = []
@shard_keys = shards.keys
if shards.empty?
shards[:default] = database
end
self.default_shard = shards.keys.first
shards.each do |shard, database_keys|
database_keys.each do |role, database_key|
db_config = resolve_config_for_connection(database_key)
self.connection_class = true
connections << connection_handler.establish_connection(db_config, owner_name: self, role: role, shard: shard.to_sym)
end
end
connections
end Подключает модель к указанным базам данных. Ключевое слово database принимает хеш, содержащий role и database_key.
Это позволит найти конфигурацию базы данных, используя database_key, и установить подключение к этой конфигурации.
class AnimalsModel < ApplicationRecord
self.abstract_class = true
connects_to database: { writing: :primary, reading: :primary_replica }
end
connects_to также поддерживает горизонтальное фрагментирование. API горизонтального фрагментирования также поддерживает реплики чтения. Вы можете подключить модель к списку фрагментов так:
class AnimalsModel < ApplicationRecord
self.abstract_class = true
connects_to shards: {
default: { writing: :primary, reading: :primary_replica },
shard_two: { writing: :primary_shard_two, reading: :primary_shard_replica_two }
}
end
Возвращает массив подключений к базам данных.
# File activerecord/lib/active_record/connection_handling.rb, line 50 def establish_connection(config_or_env = nil) config_or_env ||= DEFAULT_ENV.call.to_sym db_config = resolve_config_for_connection(config_or_env) connection_handler.establish_connection(db_config, owner_name: self, role: current_role, shard: current_shard) end
Устанавливает подключение к базе данных. Принимает хеш в качестве входных данных, где ключевое :adapter должно быть указано с именем адаптера базы данных (в нижнем регистре). Пример для обычных баз данных (MySQL, PostgreSQL и т. д.):
ActiveRecord::Base.establish_connection( adapter: "mysql2", host: "localhost", username: "myuser", password: "mypass", database: "somedatabase" )
Пример для базы данных SQLite:
ActiveRecord::Base.establish_connection( adapter: "sqlite3", database: "path/to/dbfile" )
Также принимает ключи как строки (например, для парсинга из YAML):
ActiveRecord::Base.establish_connection( "adapter" => "sqlite3", "database" => "path/to/dbfile" )
Или URL:
ActiveRecord::Base.establish_connection( "postgres://myuser:mypass@localhost/somedatabase" )
В случае, если ActiveRecord::Base.configurations задано (Rails автоматически загружает содержимое config/database.yml в него), в качестве аргумента также может быть указана строка, представляющая ключ в хеше конфигурации:
ActiveRecord::Base.establish_connection(:production)
Исключения AdapterNotSpecified, AdapterNotFound и ArgumentError могут быть возвращены при ошибке.
# File activerecord/lib/active_record/connection_handling.rb, line 269 def lease_connection connection_pool.lease_connection end
Возвращает подключение, текущее для класса. Это также можно использовать для «одолжения» подключения для выполнения работы с базой данных, не связанной с конкретными Active Record. Подключение остается взятым в аренду на всё время запроса или задания, или до вызова #release_connection.
# File activerecord/lib/active_record/connection_handling.rb, line 211 def prohibit_shard_swapping(enabled = true) prev_value = ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = enabled yield ensure ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] = prev_value end
Запрещает переключение фрагментов во время выполнения переданного блока.
В некоторых случаях вам может потребоваться возможность переключаться между фрагментами, но не допускать вложенного вызова connected_to или connected_to_many для повторного переключения. Это полезно в тех случаях, когда вы используете фрагментирование для обеспечения изоляции базы данных на каждый запрос.
# File activerecord/lib/active_record/connection_handling.rb, line 298 def release_connection connection_pool.release_connection end
Возвращает текущее подключение, взятое в аренду, в пул.
# File activerecord/lib/active_record/connection_handling.rb, line 355
def remove_connection
name = @connection_specification_name if defined?(@connection_specification_name)
# if removing a connection that has a pool, we reset the
# connection_specification_name so it will use the parent
# pool.
if connection_handler.retrieve_connection_pool(name, role: current_role, shard: current_shard)
self.connection_specification_name = nil
end
connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
end # File activerecord/lib/active_record/connection_handling.rb, line 346 def retrieve_connection connection_handler.retrieve_connection(connection_specification_name, role: current_role, shard: current_shard) end
# File activerecord/lib/active_record/connection_handling.rb, line 376 def shard_keys connection_class_for_self.instance_variable_get(:@shard_keys) || [] end
# File activerecord/lib/active_record/connection_handling.rb, line 220 def shard_swapping_prohibited? ActiveSupport::IsolatedExecutionState[:active_record_prohibit_shard_swapping] end
Определяет, запрещена ли переключение фрагментов в данный момент
# File activerecord/lib/active_record/connection_handling.rb, line 380 def sharded? shard_keys.any? end
# File activerecord/lib/active_record/connection_handling.rb, line 235 def while_preventing_writes(enabled = true, &block) connected_to(role: current_role, prevent_writes: enabled, &block) end
Запрещает запись в базу данных независимо от роли.
В некоторых случаях вам может потребоваться предотвратить запись в базу данных, даже если вы работаете с базой данных, которая может записывать. while_preventing_writes предотвратит запись в базу данных на время выполнения блока.
Этот метод не обеспечивает той же защиты, что и пользователь с правами только для чтения, и предназначен для защиты от случайных записей.
См. READ_QUERY для запросов, которые блокируются этим методом.
# File activerecord/lib/active_record/connection_handling.rb, line 309 def with_connection(prevent_permanent_checkout: false, &block) connection_pool.with_connection(prevent_permanent_checkout: prevent_permanent_checkout, &block) end
Выдаёт подключение из пула, передает его, а затем возвращает обратно. Если соединение уже было получено с помощью lease_connection или родительского вызова with_connection, это же соединение передаётся. Если lease_connection вызывается внутри блока, соединение не возвращается в пул. Если connection вызывается внутри блока, соединение не будет возвращено в пул, если prevent_permanent_checkout не установлен в true.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.