I am attempting to use the acts_as_tenant gem to scope SQL queries for multiple organizations. RSpec/FactoryGirl are pulling some dirty tricks, however.
A bit of background: in my app, User and Grant both belong to an Organization. Only admin users can create/delete Grants.
Like the gem's documentation advises, I have inserted acts_as_tenant :organization into my Grant and User models. I have also set_current_tenant_through_filter and defined a before_action :set_organization in my application_controller.rb. Queries for User and Grant are scoped to the current user's Organization only:
def set_organization
if current_user
current_organization = Organization.find(current_user.organization_id)
set_current_tenant(current_organization)
end
end
All seems well and good. Now to write controller tests:
# 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
The admin part raises an odd error:
Failure/Error: let(:admin) { create(:user, admin: true, organization_id: organization.id) }
ActiveRecord::RecordInvalid:
Validation failed: Organization can't be blank
So, even though I have specifically passed the organization's foreign key to FactoryGirl, it's still having issues identifying the Organization.
When I comment out the acts_as_tenant-specific code, the errors go away. How can I make the tests go green for good?
This actually has very little to do with the code I posted above. The culprit was this line, in my
Usermodel:I believe that line prevented the actual
organization_iddatabase column from being saved with the model. MyUsersControllercode can clarify this:So
organization_idwas indeed set toorganization.id, butattr_accessorwas evaluated first, soorganization_idbecame a useless virtual attribute. And the db columnorganization_idwas saved asnil, i.e., nothing was passed to it. This in turn causedacts_as_tenantto complain since I'd set thecurrent_tenantas the current user's organization, and the current user wasn't getting set up with a foreign key.My advice to myself and to all others who stumble upon this: check whether your db column names are shadowed by your virtual attributes.