Etienne
Etienne

Reputation: 63

Validates association of an object

I have a weird case in my rails development that I'm not able to manage properly. Basically, I have three objects: Domain, Project and Person ; a domain is a group of persons and projects. Domains can have several projects and projects can have several people however a project can only be in one domain and people can only work for projects in one domain.

I have represented it as following:

class Domain < ActiveRecord::Base
    has_many :projects

class Project < ActiveRecord::Base
    belongs_to :domain
    has_and_belongs_to_many :persons

class Person < ActiveRecord::Base
    belongs_to :domain
    has_and_belongs_to_many :projects

I don't know how to validate that all the projects added to a person belongs to the same domain. I have created a method for validating persons however it is still possible to add projects in other domains, the person saved in database will just not be valid.

Do you see a clean solution to this problem?

Upvotes: 0

Views: 173

Answers (2)

Janko
Janko

Reputation: 9335

So, basically, you want to validate that a person takes projects only from one domain. I suppose this domain should be defined, meaning a person should have a domain_id column.

You also have a many-to-many association, and, since the association needs some validations, you should have also a join model (instead of just a table without a model). I called it Work. So, I have this:

class Domain < ActiveRecord::Base
  has_many :projects
end

class Project < ActiveRecord::Base
  belongs_to :domain

  has_many :works
  has_many :persons, :through => :works
end

class Work < ActiveRecord::Base
  belongs_to :project
  belongs_to :person
end

class Person < ActiveRecord::Base
  has_many :works
  has_many :projects, :through => :works
end

Now, to the Work model you just add

validate :projects_belong_to_apropriate_domains

def projects_belong_to_apropriate_domains
  if person.domain_id != project.domain.id
    errors[:base] << "A person may only take a project which belongs to his domain."
  end
end

This worked for me. Is this what you wanted?

Upvotes: 1

roo
roo

Reputation: 7196

You could setup a custom validation method for Person (taken from the rails guides)

validates :check_project_domain

def check_project_domain
  projects.all.each do |p|
    next if domains.exists?(p.domain.id)
    errors.add :project_domain "#{p} is not a member of allowed domains"
  end
end

I'm not to sure if you can call exists on a association, if not then you could replace it with something like:

domains.all.collect { |d| d.id }.include?(p.domain.id)

or even:

domains.where(:id => p.domain.id).count > 0

Upvotes: 0

Related Questions