Как обрезать все данные в схеме, отличной от общедоступной (database_cleaner)

В моем проекте я использую драгоценный камень «квартира» с несколькими арендаторами базы данных.

config/initializers/apartment.rb 

Apartment.configure do |config|
 config.excluded_models = %w{ User Company }
end

Чтобы очистить базу данных, которую он тестирует, я использую гем «database_cleaner».

spec/rails_helper.rb

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do |example|
    DatabaseCleaner.strategy= example.metadata[:js] ? :truncation : :transaction
    DatabaseCleaner.start
    Apartment::Tenant.switch!('app')
  end

  config.after(:each) do
    Apartment::Tenant.switch!
    DatabaseCleaner.clean
  end

end

В тестах RSpec со стратегией усечения Capybara очищают после каждого теста только публичную схему, где только пользователь и компания.

Before test start 
Company.count#=> 0

Другие схемы не очищаются.

Before test start
SomeModelInCompanySchema.count#=> 240

Как очистить данные в другой схеме


person melnik_vasya    schedule 22.07.2015    source источник


Ответы (1)


Я создал собственный класс для очистки тестовой базы данных

class CleanTestDatabase

  TABLE_TO_EXCLUDE = ['spatial_ref_sys', 'schema_migrations']
  CONNECTION = ActiveRecord::Base.connection

  def self.clean(*tenants)
    tenants.each{ |tenant| delete_all_in_tenant(tenant) }
  end

  def self.drop_all_schemas
    schemas = ActiveRecord::Base.connection.select_values <<-SQL
        SELECT
          schema_name
        FROM
          information_schema.schemata
        WHERE
          schema_name NOT IN ('information_schema','public', 'postgis') AND
          schema_name NOT LIKE 'pg%'
    SQL
    schemas.each { |schema| Apartment::Tenant.drop(schema) }
  end

  private

    def self.delete_all_in_tenant(tenant)
      CONNECTION.disable_referential_integrity do
        tables_to_clean(tenant).each do |table|
          delete_from(table) if table_has_new_rows?(table)
        end
      end
    end

    def self.tables_to_clean(tenant)
      tables = CONNECTION.tables - TABLE_TO_EXCLUDE
      tables.map{ |table| "#{tenant}.#{table}" }
    end

    def self.table_has_new_rows?(table_name)
      CONNECTION.select_value("SELECT count(*) FROM #{table_name}").to_i > 0
    end

    def self.delete_from(table_name)
      CONNECTION.execute("DELETE FROM #{table_name}")
    end
end

спец/rails_helper.rb

  config.before(:each) do
    CleanTestDatabase.clean('public', 'app')
    Apartment::Tenant.switch!('app')
  end
person melnik_vasya    schedule 23.07.2015
comment
Это здорово, за исключением того, что в Rails ›= 5.1 есть таблица с именем ar_internal_metadata, она вызовет ошибку ActiveRecord::NoEnvironmentInSchemaError:, если вы не поместите в нее TABLE_TO_EXCLUDE - person Kiry Meas; 17.09.2019