When using validates_uniqueness_of tests on join tables, an AssociationTypeMismatch is raised because shoulda-matchers tries to assign a string to the association instead of the association's actual type.
Here's a db/schema.rb with a join table:
create_table "organization_memberships", id: false, force: true do |t|
t.integer "organization_id", null: false
t.integer "user_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "organization_memberships", ["organization_id", "user_id"], name: "index_organization_memberships_on_organization_id_and_user_id", unique: true, using: :btree
And here's the corresponding model:
require 'active_record'
class OrganizationMembership < ActiveRecord::Base
belongs_to :user
belongs_to :organization
validates :user,
:presence => true,
:uniqueness => { :scope => :organization_id }
validates :organization,
:presence => true,
:uniqueness => { :scope => :user_id }
end
And here's a test:
it "enforces uniqueness" do
expect(subject).to validate_uniqueness_of(:user).scoped_to(:organization_id)
end
Unfortunately, this test will fail:
Failure/Error: expect(subject).to validate_uniqueness_of(:user).scoped_to(:organization_id)
ActiveRecord::AssociationTypeMismatch:
User(#70186039298000) expected, got String(#70186016877360)
That's because on this line, a string is assigned instead of an object of the association's type.
Expected result: The validation procedure should assign an object of the association's correct type, rather than an arbitrary string.
Just hit this myself, womp womp. Strangely sometimes it works, sometimes it doesn't.
This is happening to me too.
Yep, same here.
Yep - I got this bug as well.
Any workaround or proposed solution?
With some digging the above mentioned line should be at:
https://github.com/thoughtbot/shoulda-matchers/tree/0e2e9c45199ca567dce91b218f1c3d39ce7fe55a/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb#L322
I hit the same issue, if I explicitly create the item it works, so possible workaround
it "enforces uniqueness" do
expect(create(:organization_membership)).to validate_uniqueness_of(:user).scoped_to(:organization_id)
end
I'm wondering if this is less about the fact that the model is a join table, and more about the fact that the validation is on an association. I don't think validate_uniqueness_of explicitly supports that...
Just hit this myself as well.
Using @hwatkins's workaround for now.
@mcmire You are right in saying that the docs do not mention associations explicitly for uniqueness validation, but specifying associations in the validation does indeed work in Rails.
Just ran into this myself. Since no one has explicitly said it yet: the solution was (for both me and the op) to test :user_id instead of :user.
As a workaround, one can define subject with a valid persisted object :
# with factory_girl
subject { create(:user) }
# without
subject { User.create(email: '[email protected]', password: '1234', …) }
Hey folks. In an effort to lighten our load as maintainers and be able to serve you better in the future, the shoulda-matchers team is working on cleaning out the cobwebs in this repo by pruning the backlog. As there are few of us, there are a lot of items that will simply never earn our attention in a reasonable time frame, and rather than giving you an empty promise, we think it makes more sense to focus on more recent issues. That means, unfortunately, that we must close this issue.
Don't take this the wrong way: our aim is not to diminish the effort people have made or dismiss problems that have been raised. If you feel that we should reopen this issue, then please let us know so that we can reprioritize it. Thanks!
Most helpful comment
As a workaround, one can define subject with a valid persisted object :