acts_as_tenant gem 正在使用 RSpec/FactoryGirl 创建错误
acts_as_tenant gem is creating errors using RSpec/FactoryGirl
我正在尝试使用 acts_as_tenant
gem 来限定多个组织的 SQL 查询范围。然而,RSpec/FactoryGirl 正在玩一些肮脏的把戏。
一些背景知识:在我的应用程序中,User
和 Grant
都属于 Organization
。只有管理员用户可以 create/delete Grant
s.
正如 gem 的文档所建议的那样,我已将 acts_as_tenant :organization
插入到我的 Grant
和 User
模型中。我还 set_current_tenant_through_filter
并在我的 application_controller.rb
中定义了一个 before_action :set_organization
。 User
和 Grant
的查询仅限于当前用户的 Organization
:
def set_organization
if current_user
current_organization = Organization.find(current_user.organization_id)
set_current_tenant(current_organization)
end
end
一切似乎都很好。现在编写控制器测试:
# grants_controller_spec.rb
describe GrantsController do
let(:organization) { create(:organization) }
let(:admin) { create(:user, admin: true, organization_id: organization.id) }
...
before(:each) { log_in admin }
...
end
管理部分出现了一个奇怪的错误:
Failure/Error: let(:admin) { create(:user, admin: true, organization_id: organization.id) }
ActiveRecord::RecordInvalid:
Validation failed: Organization can't be blank
因此,即使我专门将组织的外键传递给 FactoryGirl,它仍然无法识别 Organization
。
当我注释掉特定于 acts_as_tenant
的代码时,错误就消失了。我怎样才能让测试永远变绿?
这其实和我上面贴的代码关系不大。罪魁祸首是这条线,在我的 User
模型中:
attr_accessor :organization_id
我认为该行阻止了实际的 organization_id
数据库列与模型一起保存。我的 UsersController
代码可以阐明这一点:
def create
@user = User.new(user_params)
organization = Organization.find_by(name: params[:user][:organization_name])
if organization.authenticated?(params[:user][:organization_password])
@user.organization_id = organization.id
@user.save
...
end
所以organization_id
确实设置为organization.id
,但是attr_accessor
被先求值了,所以organization_id
变成了无用的虚拟属性。并且数据库列 organization_id
被保存为 nil
,即没有传递给它。这反过来导致 acts_as_tenant
抱怨,因为我将 current_tenant
设置为当前用户的组织,而当前用户没有设置外键。
我对自己和所有偶然发现此问题的其他人的建议:检查您的数据库列名是否被虚拟属性遮盖了。
我正在尝试使用 acts_as_tenant
gem 来限定多个组织的 SQL 查询范围。然而,RSpec/FactoryGirl 正在玩一些肮脏的把戏。
一些背景知识:在我的应用程序中,User
和 Grant
都属于 Organization
。只有管理员用户可以 create/delete Grant
s.
正如 gem 的文档所建议的那样,我已将 acts_as_tenant :organization
插入到我的 Grant
和 User
模型中。我还 set_current_tenant_through_filter
并在我的 application_controller.rb
中定义了一个 before_action :set_organization
。 User
和 Grant
的查询仅限于当前用户的 Organization
:
def set_organization
if current_user
current_organization = Organization.find(current_user.organization_id)
set_current_tenant(current_organization)
end
end
一切似乎都很好。现在编写控制器测试:
# grants_controller_spec.rb
describe GrantsController do
let(:organization) { create(:organization) }
let(:admin) { create(:user, admin: true, organization_id: organization.id) }
...
before(:each) { log_in admin }
...
end
管理部分出现了一个奇怪的错误:
Failure/Error: let(:admin) { create(:user, admin: true, organization_id: organization.id) }
ActiveRecord::RecordInvalid:
Validation failed: Organization can't be blank
因此,即使我专门将组织的外键传递给 FactoryGirl,它仍然无法识别 Organization
。
当我注释掉特定于 acts_as_tenant
的代码时,错误就消失了。我怎样才能让测试永远变绿?
这其实和我上面贴的代码关系不大。罪魁祸首是这条线,在我的 User
模型中:
attr_accessor :organization_id
我认为该行阻止了实际的 organization_id
数据库列与模型一起保存。我的 UsersController
代码可以阐明这一点:
def create
@user = User.new(user_params)
organization = Organization.find_by(name: params[:user][:organization_name])
if organization.authenticated?(params[:user][:organization_password])
@user.organization_id = organization.id
@user.save
...
end
所以organization_id
确实设置为organization.id
,但是attr_accessor
被先求值了,所以organization_id
变成了无用的虚拟属性。并且数据库列 organization_id
被保存为 nil
,即没有传递给它。这反过来导致 acts_as_tenant
抱怨,因为我将 current_tenant
设置为当前用户的组织,而当前用户没有设置外键。
我对自己和所有偶然发现此问题的其他人的建议:检查您的数据库列名是否被虚拟属性遮盖了。