我使用gem devise
和gem apartment
来为每个设备的用户帐户创建单独的架构。
Apartment' doc和advice 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处获得。
那么..主要问题是:如何在测试后为每个用户清理数据库创建的模式?我也会感谢任何其他评论。提前感谢您的帮助。
答案 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
...
当然不是很快,但这是我找到的唯一方法。