1

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.

  • Do you mean that you can create several membership records with the same `page_id` and `user_id`? – max Sep 27 '17 at 11:59
  • Maybe we are saying the same thing but its hard to tell if you are expecting the correct result of that validation. You should provide a reproducable example (for example from the Rails console) where you show the result of for example `2.times { Membership.create!(user: User.first, page: Page.first) }`. – max Sep 27 '17 at 12:19
  • I am able to call Page.users.create name: 'user name' multiple times. –  Sep 27 '17 at 12:40
  • Unless you have a uniqueness validation for `User#name` that will create multiple users which is why the validation on `Membership` passes. Run `2.times { Membership.create!(user: User.first, page: Page.first) }` and you should see that it works. (as in that a RecordNotValid error is raised). – max Sep 27 '17 at 12:46
  • Thanks @Max, maybe am going about it the wrong way. What I would like to achieve is to NOT have same user added to a page as member multiple times. –  Sep 27 '17 at 12:47
  • Going through the Membership model worked, post it in the answers so we can close this question. –  Sep 27 '17 at 12:51

1 Answers1

4

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.

max
  • 96,212
  • 14
  • 104
  • 165