# Class can be many other..classes

**URL:** <https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008>\
**Category:** Rails\
**Created:** [May 12, 2007, 9:31pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008 "2007-05-12T21:31:20Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 9:31pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/1 "2007-05-12T21:31:20Z")

</div>

Hey All,

Before I go off on a tangent, I thought it best to see if anyone has a  
pattern for this already.

An example should explain all:

Let’s say I have a Person class and a person can be both a Teacher and  
a Performer. I feel that Teacher and Performer are classes in their  
own right as they have other things associated with them. Including  
all attributes and associations under the User class will get real  
messy, real quick.

At first I experimented with STI but obviously a class can only be one  
type.

I could also use standard associations and have this kind of set up:

person = Person.find(1)  
person.teacher.level  
person.performer.styles

This could prove to be the most straight-foward way of doing it, but I  
can’t help feeling that the definitions aren’t representative of the  
domain - and that kinda bothers me.

I feel like saying “a Person can be a Teacher and/or a Performer”…

Anyway, I’d be very interested in anyone’s thoughts on this. If there  
is a pattern out there for this that would apply to ActiveRecord then  
I’m poised to code it up.

Cheers,

Steve

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 9:38pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/2 "2007-05-12T21:38:20Z")

</div>

I don’t think inheritance/polymorphism solve your problem. You might  
look to roles (has\_many :roles, :through =\> :join\_table).

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 9:48pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/3 "2007-05-12T21:48:21Z")

</div>

> I don’t think inheritance/polymorphism solve your problem.  
> I agree.

> look to roles (has\_many :roles, :through =\> :join\_table).  
> Hmm… roles do sound more promising… I think that inheritence could  
> be used then. If I say that Teachers and Performers are Roles that  
> People have, it feels a lot more natural.

See? It’s always best to ask. You should have seen some of the ideas  
I was having for what’s actually a straight forward problem…

Cheers,

Steve

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 9:49pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/4 "2007-05-12T21:49:21Z")

</div>

Steve

> Let’s say I have a Person class and a person can be  
> both a Teacher and a Performer.

I’m sure there are better ways but what about : (untested)

```
class Person < ActiveRecord::Base
  has_many :classes
  has_many :performances

  def teacher? ; classes .empty? end
  def performer? ; performances.empty? end
end

```

## Alain R.

[http://blog.ravet.com](http://blog.ravet.com)

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 10:07pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/5 "2007-05-12T22:07:22Z")

</div>

Steve,

> Yeah that’s a nice idea but my main concern is that as the  
> application  
> grows, it will get messy with this kind of set up. For example, if  
> a  
> Person could be a Student I’d need to add yet more relationships and  
> attributes.

Personally I prefer the compact style of my first post, but I guess  
you could “modularize”/“role-arize” it :  
(untested)

```
class Person < ActiveRecord::Base
    include Teacher, Performer, Student
end

module Teacher
  def self.included(base)
    base.has_many :classes, :dependent => :destroy
  end
  def teacher? ; !classes.empty? end
end

module Student ..

module Performer ..

```

Even with 3 roles I still prefer the compactness of :

```
class Person < ActiveRecord::Base
   has_many :classes , :dependent => :destroy
   has_many :performances, :dependent => :destroy
   has_many :enrolments , :dependent => :destroy

  def teacher? ; !classes .empty? end
  def performer? ; !performances.empty? end
  def student? ; !enrolments .empty? end
end

```

## Alain R.

[http://blog.ravet.com](http://blog.ravet.com)

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 9:56pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/6 "2007-05-12T21:56:22Z")

</div>

Alain,

Yeah that’s a nice idea but my main concern is that as the application  
grows, it will get messy with this kind of set up. For example, if a  
Person could be a Student I’d need to add yet more relationships and  
attributes.

The Roles idea suggested by s.ross will allow me to organise my  
classes neatly and there’s room for expansion as the application  
grows.

Cheers,

Steve

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 10:46pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/7 "2007-05-12T22:46:25Z")

</div>

Steve,

> I originally thought that I wanted to be able to do this:  
> Teacher.find(:all)

The simplest shortest (but slowest) way that works :

teachers = Person.find(:all).select(&:teacher?)

(Don’t use if you have more than xxx people in your DB)

## Alain R.

[http://blog.ravet.com](http://blog.ravet.com)

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 10:28pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/8 "2007-05-12T22:28:24Z")

</div>

Actually, you know what? I think you may be right. I just started  
explaining why I thought the multiple model idea was better and  
realised that it was actually no better than my original idea of using  
relationships.

I want to avoid this:

person.teacher.regular\_classes

So your idea of putting all the relationships in the Person class  
achieves that. I originally thought that I wanted to be able to do  
this:

Teacher.find(:all)

but to be honest, I think I might be better off having ‘teacher’,  
‘student’, ‘performer’ attributes in my people table and use those.  
Seeing as a Person could be all 3 roles there’s nothing messy about  
having the attributes and associations in the same class.

Cheers,

Steve

---

<div class="post-metadata">

**Author:** ![stepheneb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/71e660/32.png) [@stepheneb](https://www.ruby-forum.com/u/stepheneb)\
**Post date:** [May 12, 2007, 11:10pm UTC](https://www.ruby-forum.com/t/class-can-be-many-other-classes/104008/9 "2007-05-12T23:10:27Z")

</div>

If you know that the only three roles a person can assume are  
teacher, student, and performer, then you’re in good shape with this  
solution. It’s when you get a few months down the road and you have  
to add hall\_monitor or class\_clown that you begin to have issues with  
hard-typing instead of relational (role-based).
