Reputation: 2364
I have these models in Rails 6.1.7:
class AdminUser < ApplicationRecord
belongs_to :organization, foreign_key: 'type_id'
end
class OrganizationUser < AdminUser
end
and defined in the file spec/fabricators/admin_user_fabricator.rb :
Fabricator(:admin_user) do
email { Forgery(:internet).email_address }
first_name { Forgery(:name).first_name }
last_name { Forgery(:name).last_name }
end
Fabricator(:organization_user, from: :admin_user, class_name: :organization_user) do
organization
end
but when I try to fabricate the attributes in my Rspec test:
Fabricate.attributes_for(:organization_user)
I'm getting:
{"email"=>"[email protected]", "first_name"=>"Carolyn", "last_name"=>"Gutierrez", "organization_id"=>6919}
F
Failures:
ActiveModel::UnknownAttributeError:
unknown attribute 'organization_id' for OrganizationUser.
So, the attribute "organization_id" shouldn't be there. Besides, the attributes "type"=>"OrganizationUser" and "type_id"=>6939 should be there.
I don't haven experience with this gem yet. I tried several changes, but no luck so far. I don't know what I'm doing wrong.
Upvotes: 1
Views: 108
Reputation: 456
There seems to be some confusion between your database tables structure, your models and the way Fabrication gem works.
type
fieldIt looks like you're working with Single Table Inheritance, so it makes sense to expect your database table to contain the type
column. And you can verify that by running OrganizationUser.column_names
or AdminUser.column_names
. If STI was generated correctly, you should see the type
column listed there.
This column will be automatically set whenever you instantiate an object for the child class.
> OrganizationUser.new.type
=> "OrganizationUser"
And a similar result is expected if you build an OrganizationUser
object with fabrication:
> organization_user = Fabricate.build(:organization_user)
> organization_user.type
=> "OrganizationUser"
However, when you call Fabricate.attributes_for
, you're not instantiating a model object. attributes_for
only loads what's present in the definitions for your fabrications. That's why you don't see the type
field listed there. Your fabricators have no type
field. If you want it to be returned, you must explicitly add type "OrganizationUser"
to your organization_user
fabricator.
organization_id
attribute and the type_id
columnThe organization_id
attribute is returned when you call for Fabricate.attributes_for(:organization_user)
because you specified the association
relation in your fabricator. Similar to the topic above, note that attributes_for
will return a list according to your fabricator definitions. If an association is passed, it will try to generate an ID based on it (regardless of which foreign key you defined in your model).
I don't see much about Organization
in your question.
I'm assuming you also have an organizations
table and an Organization
model and that you added a type_id
column to the admin_users
table. You might want to go through those steps if any of these assumptions are incorrect. I'd suggest not using the type_id
name for that FK unless you have a strong reason for that choice. If you could stick to the conventional FK organization_id
, that can make your code easier to follow.
Assuming you're keeping type_id
as the FK, you could have something like the following:
Fabricator(:organization_user, from: :admin_user, class_name: :organization_user) do
type "OrganizationUser"
type_id { Fabricate(:organization).id }
end
And then you call it on your specs without the need for extra params:
attributes = Fabricate.attributes_for(:organization_user)
Upvotes: 2
Reputation: 2364
As Lidiane suggested, I fixed the issue with:
let(:orguser_attrs) { Fabricate.attributes_for(:organization_user, type: 'OrganizationUser', type_id: Fabricate(:organization).id).except(:organization_id) }
Yeah, ugly as heck, I know. Bad designed models.
Upvotes: 0