0

我正在尝试使用acts_as_tenantgem 来确定多个组织的 SQL 查询范围。然而,RSpec/FactoryGirl 正在使用一些肮脏的技巧。

一点背景知识:在我的应用程序中,User两者Grant都属于Organization. 只有管​​理员用户可以创建/删除Grants。

就像 gem 的文档建议的那样,我已经插入acts_as_tenant :organization了我的GrantUser模型。我也在我set_current_tenant_through_filter的. 查询和仅限于当前用户:before_action :set_organizationapplication_controller.rbUserGrantOrganization

  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特定代码时,错误就会消失。我怎样才能让测试永远变绿?

4

1 回答 1

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

soorganization_id确实设置为organization.id,但attr_accessor先被求值,所以organization_id变成了无用的虚拟属性。并且 db 列organization_id被保存为nil,即没有任何东西传递给它。这反过来又引起acts_as_tenant了抱怨,因为我将 设置current_tenant为当前用户的组织,并且当前用户没有设置外键。

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

于 2015-07-17T23:51:47.267 回答