1

我有gem devise并且gem apartment我正在使用它为每个设计的用户帐户创建单独的模式。

Apartment在该问题中的文档和建议建议使用 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

应用程序/模型/用户.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

所有来源的当前提交都可以在我的 github 上找到

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

4

2 回答 2

5

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

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

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

这有帮助吗?

于 2014-05-20T00:38:55.570 回答
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
...

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

于 2017-01-25T01:28:00.330 回答