1

My models are

class Company
  has_many :admins

  validate :has_one_admin_validation

  private

  def has_one_admin_validation
    errors.add(:admins, :not_enough) if admins.size < 1
  end

end

class Admin
  belong_to :company
end

Now, suppose I have a controller that can remove admins. How do I prevent removing the admin (ie generate errors) if it is the only admin of its company ?

If I understand well, I have to remove the admin from the memory object, and try to "save/destroy" if by validating the company first ?

Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164
  • notice there is [validates_associated](http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html) – niceman Jun 16 '16 at 19:54
  • hmm but maybe this validation belongs to the Admin class , not sure though – niceman Jun 16 '16 at 19:55

1 Answers1

2

I don't think you need a custom validation at all on the Company model. You can use the 'length' validation on your association.

validates :admins, length: { minimum: 1 }

If that doesn't work, you should also be able to check the 'marked_for_destruction?' property. You should also be able to validate the reciprocal relationship with a 'presence: true' validation.

    class Company
        has_many :admins

        validate :has_one_admin_validation

        private

        def has_one_admin_validation
          errors.add :admins, "You need at least one admin" if admins.reject(&:marked_for_destruction?).empty?
        end

    end

    class Admin
        belongs_to :company, presence: true
    end

You may also want to look at using the before_destroy callback in your Admin class.

before_destroy :has_company_with_no_other_admins
        ...

        private

        def has_company_with_no_other_admins
          return false if company.admins.length < 2
          true
        end

There's a pretty good description of using before_destroy here: https://stackoverflow.com/a/123190/6441528 That's worth looking at because implementations vary based on your Rails version.

Community
  • 1
  • 1
hightempo
  • 469
  • 2
  • 8
  • 1
    hmmm will this validation run on Admin delete ? notice that the validation is present in Category class or maybe it should be put in the Admin Class ? – niceman Jun 16 '16 at 19:50
  • Hi! I'm not OP but I have a project where I can use something like this. Say that I have a model with a has_one associated model, will this help me enforce a limit of 1 associations for that model? Cheers and thanks! – Alfredo Gallegos Jun 16 '16 at 19:58
  • @AlfredoGallegos `has_one` alone is enough, no need for validations, in fact adding more than 1 will result in a Ruby runtime exception(NoMethodError perhaps) – niceman Jun 16 '16 at 20:01
  • The thing is, in that project somehow I'm able to establish more than one relationship even though my models have has_one/belongs_to. I think it's a goof on my side then, so no worries :^) – Alfredo Gallegos Jun 16 '16 at 20:07
  • @niceman - I think you may be correct that I misunderstood the question somewhat and didn't add the reciprocal validation to Admin. I've edited my answer accordingly to add the 'presence:true' modifier to the Admin class. – hightempo Jun 16 '16 at 20:10
  • @AlfredoGallegos - I agree with niceman -- I think that should work. If you're still having problems, perhaps you should post your code in a new question so people can look at it in context. – hightempo Jun 16 '16 at 20:12
  • Shouldn't the `before_destroy` check for `company.admins.length < 2` then ? `<2` means there's still another admin for the company in case the current one gets destroyed ? – Cyril Duchon-Doris Jun 16 '16 at 21:03
  • @CyrilDuchon-Doris - yes, you are right since the callback gets processed before the record is actually destroyed. – hightempo Jun 16 '16 at 21:31
  • Oh also, since I am on Rails 5, I need to `throw(:abort)` right ? – Cyril Duchon-Doris Jun 17 '16 at 15:46
  • Yes, Rails 5 requires an actual error to be thrown in this case. – hightempo Jun 17 '16 at 17:49