shoulda matchers should validate_uniqueness_of failing with scope
Asked Answered
M

4

12

I have 3 models, user, game, and player. There's basically a many to many relationship between users and games, with players as the join table, except players have other info so it has its own model.

A player needs a unique combo of game id and user id, so I tried to say in player:

validates_uniqueness_of :user_id, :scope => :game_id

and then in my spec, I said (using shoulda matchers):

it { should validate_uniqueness_of(:user_id).scoped_to(:game_id)}

here are the relationships the player defines:

belongs_to :game, :inverse_of => :players
belongs_to :user, :inverse_of => :players

yet I'm getting an ActiveRecord::statementinvalid error on that spec

ActiveRecord::StatementInvalid: Mysql2::Error: Column 'game_id' cannot be null: INSERT INTO `players` ETC...

Any idea what's going wrong?

Milled answered 28/4, 2013 at 21:32 Comment(0)
N
9

It is a known issue. It gives this error if the scoped field is dependent on the model and is also set to :null => false.

Also, do have a look at rails Column cannot be null:

Negotiant answered 28/4, 2013 at 21:55 Comment(1)
Update: this will be fixed in v 2.7. See: github.com/thoughtbot/shoulda-matchers/commit/…Curd
C
9

While this is a known issue, there is a way around it.

If you first create a record and then test the uniqueness validation, it will work.

So, instead of simply writing

it { should validate_uniqueness_of(:user_id) }

You can write

it do
  FactoryGirl.create(:player)
  should validate_uniqueness_of(:user_id)
end

And the uniqueness validation spec will work.

Reference: http://rubydoc.info/github/thoughtbot/shoulda-matchers/master/frames

Curd answered 26/12, 2013 at 21:57 Comment(1)
or it { expect(create(:label)).to validate_uniqueness_of(:value).scoped_to(:question_id) } to get everything on one smooth line with rspec3 syntax.Dikdik
F
4

For people having this issue today here is a newer solution.

Add a subject so that the tests have a record with values.

Also, note the newer RSpec syntax.

    subject { create(:player) }

    it { is_expected.to validate_uniqueness_of(:user_id).scoped_to(:game_id)}

Check out the file on github for more info

Firework answered 16/5, 2018 at 16:26 Comment(0)
A
1

You can read about the issue and solutions mentioned in the official source code caveat here

One solution is:

describe Player do
  describe "validations" do
    it do
      expect(Player.new(game_id: 1)).
        to validate_uniqueness_of(:user_id).
        scoped_to(:game_id)
    end
  end
end
Ananna answered 7/1, 2015 at 19:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.