postgres模式的数据库清理

时间:2014-05-19 20:36:04

标签: ruby-on-rails postgresql rspec devise database-cleaner

我使用gem devisegem apartment来为每个设备的用户帐户创建单独的架构。

Apartment' docadvice in that issue建议使用Rack中间件在租户之间切换。在这种情况下,它是不可能的(据我所知)因为我有用户依赖而不是请求依赖。

除了我的RSpec测试之外,所有工作都很棒。问题是每个测试数据库都没有正确清理后(它没有删除新创建用户的模式)。如果我运行了一小部分测试,那么所有测试都会通过,但如果我运行的时间超过Faker::Internet.first_name,则会生成已经采用的用户名(无效)。

所以我就这样做了:

应用/控制器/ application_controller.rb

def scope_tenant
  Apartment::Database.switch(current_user.username)
end

app / controllers / albums_controller.rb (专辑型号belong_to :user

class AlbumsController < ApplicationController
  before_action :authenticate_user! # devise magic
  before_action :scope_tenant

应用/模型/ user.rb

after_create :create_schema

private

  def create_schema    
    Apartment::Database.create(self.username)
  end  

这是我在规格中添加的内容:

规格/工厂/ user.rb

FactoryGirl.define do
  factory :user do
    username { Faker::Name.first_name }
    email { Faker::Internet.email("#{username}") }
    password "login_as will not use it anyway"
  end
end

规格/支持/ auth_helpers.rb

Warden.test_mode!

def login_and_switch_schema(user)
 login_as(user)
 Apartment::Database.switch(user.username)    # for some reason `login_as()` didn't do that by itself
end

规格/特征/ albums_spec.rb

feature "Album Pages" do

  given(:user) { create(:user) }
  given(:album) { create(:album) }

  around :each do
    login_and_switch_schema user
  end

  scenario...

因为我对js: true进行了一些测试而不是我的测试:

规格/支持/ database_cleaner.rb

RSpec.configure do |config|

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

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

end

所有来源的当前提交均可在my github here处获得。

那么..主要问题是:如何在测试后为每个用户清理数据库创建的模式?我也会感谢任何其他评论。提前感谢您的帮助。

2 个答案:

答案 0 :(得分:5)

这不是以任何方式特定于Apartment,它与DatabaseCleaner清理数据库的方式有关。使用事务时,也将回滚在该事务中创建的任何模式。但不幸的是,您需要截断功能规范,因为事务不起作用(不要尝试共享连接'解决方案',它会因竞争条件而导致随机故障)。因此,对于您的功能规范,您需要一种方法来确保删除任何创建的模式,因为截断只会截断表并且不会清除模式。

我建议隔离专门测试多租户行为的功能规范,以确保它按照您希望的方式工作,并手动清理这些规范中创建的任何模式。然后,对于其余的功能规范,假设您在一个租户中进行测试,或者在一个用户中进行测试。

我们在测试套件中执行此操作,新的Company模型会在其中创建新的tenant。因此,对于多个租户,我们测试该行为,然后对于我们在1个公司内运行的其余功能,我们不再需要担心清理,我们可以截断该1个租户中的表。截断将始终截断当前租户中的表,除非您有excluded_models

这有帮助吗?

答案 1 :(得分:0)

现在处理截断和多租户应用程序的另一种方法是创建租户并在每次测试时删除它。像这样:

在你的rails_helper.rb上:

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

  config.before(:each) do
    Apartment::Tenant.drop('test') rescue nil
    Company.create! name: "LittleCompany", subdomain: "test"
    DatabaseCleaner.start
    Apartment::Tenant.switch! "test"
  end

  config.after(:each) do
    Apartment::Tenant.reset
    DatabaseCleaner.clean
    Apartment::Tenant.drop('test')
  end
...

当然不是很快,但这是我找到的唯一方法。