acts_as_tenant gem 正在使用 RSpec/FactoryGirl 创建错误

acts_as_tenant gem is creating errors using RSpec/FactoryGirl

我正在尝试使用 acts_as_tenant gem 来限定多个组织的 SQL 查询范围。然而,RSpec/FactoryGirl 正在玩一些肮脏的把戏。

一些背景知识:在我的应用程序中,UserGrant 都属于 Organization。只有管​​理员用户可以 create/delete Grants.

正如 gem 的文档所建议的那样,我已将 acts_as_tenant :organization 插入到我的 GrantUser 模型中。我还 set_current_tenant_through_filter 并在我的 application_controller.rb 中定义了一个 before_action :set_organizationUserGrant 的查询仅限于当前用户的 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 设置为当前用户的组织,而当前用户没有设置外键。

我对自己和所有偶然发现此问题的其他人的建议:检查您的数据库列名是否被虚拟属性遮盖了。