kevin lopez
kevin lopez

Reputation: 87

Rails has_many model validation

Hey guys currently working with a couple of models that are associated to each other. The associations are working great, but im trying to limit the amount of users that can belong to the care teams model, ive tried the validate method below and it doesnt seem to raise any error or anything. users can keep adding themselves to that team im trying to limit the amount to. any ideas?

user.rb

class User < ApplicationRecord
   devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable 
   validates_presence_of :phone, :city, :state, :street, :zip, presence: true, on: :create

   belongs_to :care_team, optional: true
end

care-team.rb

class CareTeam < ApplicationRecord
   NUMBER_OF_PERMITTED_USERS = 3 

   belongs_to :user, optional: true 

   has_many :users

   validate :validate_user_limit

   private
      def validate_user_limit(user)
         raise Exception.new if users.count > NUMBER_OF_PERMITTED_USERS
      end 
end

Upvotes: 2

Views: 2421

Answers (2)

Ilya Konyukhov
Ilya Konyukhov

Reputation: 2791

As documentation says, the method collection<<(object, …)

Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. Note that this operation instantly fires update SQL without waiting for the save or update call on the parent object, unless the parent object is a new record. This will also run validations and callbacks of associated object(s).

It means that when you add a user to care team, such as

care_team.users << user

the user is added immediately. You don't need to call care_team.save to save changes. CareTeam's validation won't be applied. That's because the changes are happening in user object: its care_team_id attribute is set to care_team.id, and then the user is saved if all its validations pass.

So you could apply your restriction by changing your validation in CareTeam in this way:

def validate_user_limit
  if users.count > NUMBER_OF_PERMITTED_USERS
    errors[:base] << "This care team has already enough users"
  end
end

and call care_team.save explicitly to make validation happen. However, it does not fix the problem at all: by that moment user is already added to care team. Validation will fail, but the user remains in the care team.

To fix the problem the validation should be moved to User model:

class User < ApplicationRecord
  validate :validate_care_team_user_limit

  private

  def validate_care_team_user_limit
    if care_team_id && User.where(care_team_id: care_team_id).count >= CareTeam::NUMBER_OF_PERMITTED_USERS
      errors.add(:care_team_id, "User cannot be added to that care team")
    end
  end
end

Upvotes: 5

arieljuod
arieljuod

Reputation: 15838

You souldn't raise exceptions on validations, just add the error if the condition is true:

def validate_user_limit #the (user) param does not go here
  self.errors.add(:users, "Too many users") if users.count > NUMBER_OF_PERMITTED_USERS
end

If you want to get an exception with an invalid record then use save! instead of save which returns false for invalid records.

Upvotes: 0

Related Questions