# Enforce mutual exclusivity

**URL:** <https://www.ruby-forum.com/t/enforce-mutual-exclusivity/114108>\
**Category:** Ruby\
**Created:** [September 8, 2007, 12:00am UTC](https://www.ruby-forum.com/t/enforce-mutual-exclusivity/114108 "2007-09-08T00:00:54Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Toby\_OSRourke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ac91a4/32.png) [@Toby\_OSRourke](https://www.ruby-forum.com/u/Toby_OSRourke)\
**Post date:** [September 8, 2007, 12:00am UTC](https://www.ruby-forum.com/t/enforce-mutual-exclusivity/114108/1 "2007-09-08T00:00:54Z")

</div>

Hi,

First post, sorry if this is the wrong place or has been answered  
before.

I’m using ActiveRecord and I want to enforce mutual exclusivity on a  
has\_and\_belongs\_to\_many.

A concrete example: I have a User which can have one or more Roles  
(student, tutor, headmaster, administrator etc). However if a user is a  
student they cannot hold any other role. I was hoping to find something  
like validate\_exclusive but that doesn’t appear to exist. Can anyone  
suggest how I can implement this. Otherwise, is there a better pattern  
I could use to model this?

Many thanks,

Toby.

---

<div class="post-metadata">

**Author:** ![Toby\_OSRourke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ac91a4/32.png) [@Toby\_OSRourke](https://www.ruby-forum.com/u/Toby_OSRourke)\
**Post date:** [September 8, 2007, 1:16am UTC](https://www.ruby-forum.com/t/enforce-mutual-exclusivity/114108/2 "2007-09-08T01:16:01Z")

</div>

On Sep 7, 2007, at 4:59 PM, Toby O’Rourke wrote:

> is a student they cannot hold any other role. I was hoping to find  
> something like validate\_exclusive but that doesn’t appear to exist.  
> Can anyone suggest how I can implement this. Otherwise, is there a  
> better pattern I could use to model this?
> 
> Many thanks,
> 
> Toby.

It’s a design pattern that occurs frequently with CRUD applications,  
in Rails or anywhere else.  
I think of this pattern as the “category” pattern.  
Basically you want an ‘option list’ (in xhtml ) and to generate that  
in Ruby/Rails you have tons of options.  
Creating an option list /drop down list is covered well in AWDWR.

One way is to hard code it:  
You can define a constant array or hash in your model file to provide  
a list from.  
(not all models have to be in the database)

Another way is to store it (more flexible, search and sort  
capabilities are closer to ready to go):  
You could also simply create a model and subsequent migration and db  
table that contains the categories for this.

Then have your User model belongs\_to category (singular!) and Users  
have a category\_id, integer column in the db table.

Since you’re using a drop down list in the interface, there will only  
be one choice.  
You could even make it more complicated with authentication  
preventing certain users from being in certain categories, but at  
that point things get messy and you might want to carefully review  
the design.

If you want to just do it with validation, you can write your own  
validates\_as  
In it, you just need a list of validations (think about  
capitalization, since it does matter) and you can use exclusive  
(a.k.a. XOR) or logic to match them. You could also try a case  
statement, but validations might barf on that.  
If you use the exclusive or approach, you’ll need to repeat the list  
of valid options in the error message of your validates\_as\_something

This is more of a Rails question, because it focuses on Rails models.  
But in them, you can use a lot of Ruby.  
You should get AWDWR or Ruby for Rails or Rails Cookbook.

The solutions can be more or less Rubyish, but all revolve around Rails.  
You could try the Rails Talk list, but you might not get as good of  
an answer there for this question as you might find in a good book.

---

<div class="post-metadata">

**Author:** ![Toby\_OSRourke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ac91a4/32.png) [@Toby\_OSRourke](https://www.ruby-forum.com/u/Toby_OSRourke)\
**Post date:** [September 9, 2007, 12:14am UTC](https://www.ruby-forum.com/t/enforce-mutual-exclusivity/114108/3 "2007-09-09T00:14:07Z")

</div>

On 9/7/07, Toby O’Rourke [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hi,
> 
> First post, sorry if this is the wrong place or has been answered before.
> 
> I’m using ActiveRecord and I want to enforce mutual exclusivity on a  
> has\_and\_belongs\_to\_many.
> 
> A concrete example: I have a User which can have one or more Roles  
> (student, tutor, headmaster, administrator etc). However if a user is a  
> student they cannot hold any other role.

Despite the knee jerk reaction to direct you to the rails mailing  
list, the real place to ask this question would be some group / list  
dedicated to data modelling in RDBMSs. That said I think it’s an  
interesting question so I’m going to try and answer it 🙂

If student is the only that is mutual exclusive with any other role,  
then one way to look at it is that student is not actually a role. One  
way to do this is to pull out all the common information about a  
person (name, address, phone number, what have you) and stick that  
into a person\_info relation. You then an have two relations, students,  
and nonstudents. Both of these would simply have a field refererring  
to the primary key of the person\_info relation. Then your relation for  
the roles would pair roles with nonstudents.

This has problems of course. If student isn’t the only exclusive role,  
or if the rules are more complicated (like a headmaster can’t be a  
tutor but they are an administrator) this kind of arrangement will  
fall apart pretty quickly.

Another option is to divide the roles into N groups of mutually  
exclusive roles, and have N fields in your relation. The problem with  
this is that you might not be able to divide your roles like this. It  
is also, like my first suggestion, brittle with respect to changes in  
the rules of what roles are mutually exclusive.

Yet another option is to enumerate all legal role combos, and  
associate each combo with an id. Then to assign a role or a set of  
roles you just use the id.
