ruby-on-railsruby-on-rails-4mongoidmongoid4

mongoid-4 how to validate uniqueness of belongs_to in 1 to 1 association


I have a 1-to-1 association between 2 mongoid models and I keep getting duplicates, that is having more than one child record(card) with same parent_id(that is user). I have tried validating uniqueness of the belongs_to association has shown below, but it doesn't work.

 class User
   include Mongoid::Document
   field :name, type: String 
   has_one :card
 end

The second model:

 class Card
   include Mongoid::Document
   field :name, type: String 
   belongs_to :user

   validates :user, :uniqueness => {:scope => :user_has_child}

   def user_has_child
     q = Segment.where(drop_id: {'$ne' =>  nil})
     s = q.map(&:drop_id)
     errors.add(:drop_id, "this user already has a card") if s.include?(:drop_id)
   end

 end

Solution

  • The syntax is more simple. You just want to make sure there are no 2 documents with the same user_id

    class Card
      belongs_to :user
    
      validates_uniqueness_of :user
    

    You need to use scope if you want the uniqueness of a tuple of n fields. For example, if a User can have at most one card per year, you can write

    class Card
     field :year
     belongs_to :user  
    
     validates_uniqueness_of :user, scope: [:year] # A user can have one card per year
    

    Note that validations apply when you save the model ie. you try to persist the changes. Calling .save will return true or false if some validations fail, but the object in memory is always modified! This is so, for example, you can display previous values in the HTML input fields, so the user knew what he wrote and can fix it (otherwise he'd have to re-write all his information in case of a single mistake)

    Also, Mongoid by default handles dirty tracking (this is now the doc for v5.0 but it was the same for Mongoid 4). That is to say, you can call .changed? .changes, etc on the object in memory to see what are the changes compared to the object in the DB.