simple role system through associative table

So I have the Ninja model which has many Hovercrafts through
ninja_hovercrafts (which stores the ninja_id and the hovercraft_id).

It is of my understanding that this kind of arrangement should be set
in a way that the associative table stores only enough information to
bind two different classes.

But I'd like to use the associative table to work as a very
streamlined authorization hub on my application. So i'd also like this
table to inform my system if this binding makes the ninja the pilot or
co-pilot of a given hovercraft, through a "role" field in the table.

My questions are:

Is this ugly?

Is this normal?

Are there methods built into rails that would help me to automagically
create Ninjas and Hovercrafts associations WITH the role? For exemple,
could I have a nested form to create both ninjas and hcs in a way that
the role field in ninjas_hovercrafts would be also filled?

If managing my application roles this way isn't a good idea, whats the
non-resource heavy alternative (my app is being designed trying to
avoid scalability problems such as excessive joins, includes, etc)

thank you


Adding attributes to the HMT model is an acceptable practice. Originally HABTM was used for many-to-many relationships and it assumed a simple table in the middle with the related ids. The problem was that the relationship table often needed to become a model of its own with additional attributes. This is why HMT came about and is the preferred method for many-to-many relationships.

I am not aware of a way to create all three models with the role in the field as you described. I believe you will have to code that in the controller.

If you do something like this and the association will set the role value for you…

class Pilot < ActiveRecord::Base

belongs_to :ninja

belongs_to :hovercraft


class Hovercraft < ActiveRecord::Base

has_many :pilots

has_many :piloted, :conditions => {:role => ‘pilot’}, :class_name => “Pilot”

has_many :copiloted, :conditions => {:role => ‘co-pilot’}, :class_name => “Pilot”

has_many :ninjas, :through => :pilots

has_many :copilot_ninjas, :through => :copiloted, :source => :ninja

has_many :pilot_ninjas, :through => :piloted, :source => :ninja


class Ninja < ActiveRecord::Base

has_many :pilots

has_many :piloted, :conditions => {:role => ‘pilot’}, :class_name => “Pilot”

has_many :copiloted, :conditions => {:role => ‘co-pilot’}, :class_name => “Pilot”

has_many :hovercrafts, :through => :pilots

has_many :copiloted_hovercrafts, :through => :copiloted, :source => :hovercraft

has_many :piloted_hovercrafts, :through => :piloted, :source => :hovercraft


Then you can do stuff like this…

Create hovercraft

hovercraft = …

Create pilot ninja

pilot_ninja = …

Create co-pilot ninja

copilot_ninja = …

Associate ninjas to hovercrafts

hovercraft.piloted.create(:ninja => pilot_ninja)

hovercraft.copiloted.create(:ninja => copilot_ninja)

Anthony Crumley