ruby-on-railsrubyvalidationhas-many-throughvalidates-uniqueness-of

Uniqueness validation not working on has_many :though association on rails 5


Models

class User < ApplicationRecord
    has_many :memberships
    has_many :pages, through: :memberships 
end

class Page < ApplicationRecord
    has_many :memberships
    has_many :users, through: :memberships 
end

class Membership < ApplicationRecord
    belongs_to :user
    belongs_to :page

    validates :page_id, uniqueness: { scope: :user_id}
end

Am able to create multiple user on pages and pages on user, it's like the validation isn't getting called.


Solution

  • To trigger the validations in a associated model you need to use validates_associated:

    class User < ApplicationRecord
      has_many :memberships
      has_many :pages, through: :memberships
      validates_associated :memberships
    end
    
    class Page < ApplicationRecord
      has_many :memberships
      has_many :users, through: :memberships
      validates_associated :memberships
    end
    
    class Membership < ApplicationRecord
      belongs_to :user
      belongs_to :page
      validates :page_id, uniqueness: { scope: :user_id}
    end
    

    This can be a real gotcha as validations on associations are not called when they are created implicitly.

    Additionally its a good idea to create a compound database index which prevents possible race conditions:

    class AddCompoundIndexToMemberships < ActiveRecord::Migration[5.0]
      def change
        add_index :memberships, [:page_id, :user_id], unique: true
      end
    end
    

    This ensures on the DB level that no two identical rows can be created.