Database Issue

So I'm having an interesting issue with my database and associations.

I have three models, Users, Groups, and Roles. They are connected via a join table that has user_id, group_id, and role_id on the same table. A user is in a group, with a role. The same user can be in another group with another (or the same) role.

So, the user model has a has_and_belongs_to_many :roles, and the role model has a has_and_belongs_to_many :users, with the appropriate tags to make it work.

With this, @user.roles will grab a list of all roles associated with that user, and @role.users will grab all the users that have that role. Duplicates are possible.

One interesting behavior, was that, if the user and the role model both had a group_id column, then when @user.roles was called (and likewise @role.users), it would grab the group_id from the join_table for each role, instead of the group_id from users or roles. If I take out the group_id from users and roles, then it does not appear when I call @user.roles

This behavior is desirable, because then it lets me do things like,

@user.roles[@user.roles.index{|x| x.group_id==1}].name

to get the name of the role that the user has in group 1. Things like that.

So my question is, how can I get that functionality (grabbing the group_id when going through the join table) without the group_id columns in the user and role tables?

I've tried declaring group_id as attr_accessor :group_id for both user and role, but that didn't work.

The most important thing is being able to maintain the behavior, that I can call @user.roles[0].group_id, and @roles.user[0].group_id, with group_id being grabbed from the join table. Any way to do that would solve my problem.

Is there a way I can do it with definitions? like def self.Role.group_id or something like that?

One interesting behavior, was that, if the user and the role model both had a group_id column, then when @user.roles was called (and likewise @role.users), it would grab the group_id from the join_table for each role, instead of the group_id from users or roles. If I take out the group_id from users and roles, then it does not appear when I call @user.roles

This behavior is desirable, because then it lets me do things like,

@user.roles[@user.roles.index{|x| x.group_id==1}].name

to get the name of the role that the user has in group 1. Things like that.

So my question is, how can I get that functionality (grabbing the group_id when going through the join table) without the group_id columns in the user and role tables?

There are two things at play here. The first is that the output of inspect (which is what you see in the rails console) never includes columns that aren't on the original table. You can still get at them by doing some_role.group_id. The second thing is related to how a habtm association is loaded What happens is that the sql that rails uses to grab your data looks something like

select * from roles inner join some_join_table on ... where some_join_table.user_id = 123

Rails grabs all the columns that come out of here but it only looks at the column name, not the table name, so if multiple tables have group_id columns they will shadow each other. Results are in theory unpredictable. I'd avoid that situation - either don't have the shadowing situation or add a select option to your has_and_belongs_to_many call that will control which columns are used.

The last thing is that most folks use has_many :through for this sort of thing - stuff just works out nicer when the join table is an actual model that you can play with

Fred