我正在尝试使用acts_as_tenant
gem来为多个组织设置SQL查询范围。然而,RSpec / FactoryGirl正在拉扯一些肮脏的技巧。
一些背景知识:在我的应用中,User
和Grant
都属于Organization
。只有管理员用户才能创建/删除Grant
s。
与gem的文档建议一样,我已将acts_as_tenant :organization
插入到我的Grant
和User
模型中。我还set_current_tenant_through_filter
并在before_action :set_organization
中定义了application_controller.rb
。 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
特定代码时,错误就会消失。如何让测试变得绿色好?
答案 0 :(得分:0)
这实际上与我上面发布的代码关系不大。罪魁祸首是我的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
成为无用的虚拟属性。 db列organization_id
保存为nil
,即没有传递给它。这反过来导致acts_as_tenant
投诉,因为我将current_tenant
设置为当前用户的组织,并且当前用户未设置外键
我对自己和偶然发现的所有其他人的建议:检查您的数据库列名是否被虚拟属性遮蔽。