how I do different has_and_belongs_to_many for the same model?

Hi,

I have a team which has and belongs to many players.

class Team < ActiveRecord::Base   has_and_belongs_to_many :players end

class Player < ActiveRecord::Base   has_and_belongs_to_many :teams end

What I'd like to do is add bench players to my team. The bench will have many players and many players can be on the bench.

I tried to do it like this:

class Team < ActiveRecord::Base   has_and_belongs_to_many :players   has_and_belongs_to_many :bench_players, :class => 'Player' end

I made the association table like this:

class TeamsBenchPlayers < ActiveRecord::Migration   def self.up     create_table :teams_bench_players, :id => false do |t|       t.column :team_id, :integer, :null => false       t.column :player_id, :integer, :null => false     end     add_index :teams_bench_players, [:team_id]     add_index :teams_bench_players, [:player_id]   end   def self.down     drop_table :teams_bench_players   end end

However when I do this:

team.bench_players << player

It saves it in the wrong table, i.e. the team_players table. What am I doing wrong?

Thanks, Frank

However when I do this:

team.bench_players << player

It saves it in the wrong table, i.e. the team_players table. What am I doing wrong?

You need to tell activerecord to use a different join table (with the :join_table) option

Fred

Some might argue that being on the bench or not is simply an attribute of a player... benched or playing, the player is still on the team.

Thanks Frederick, I forgot about that option.

Hi Ar, The attribute idea makes a lot of sense. If I did it that way then I could use the same join table. However I would have to use specify custom SQL for how to select from it, right? Or is there a better way? -Frank

Frank Kim wrote:

Hi Ar, The attribute idea makes a lot of sense. If I did it that way then I could use the same join table. However I would have to use specify custom SQL for how to select from it, right? Or is there a better way?

You could just have "benched" be a boolean field in the database. If it's true, the player's on the bench. If it's false, he's on the field. Then you can do this:

player = Player.find_by_last_name "Ronaldo" player.benched = true # Be a team player, Ronaldo!

Not sure if has_and_belongs_to_many is exactly right (can a player be on more than one team?) but one option is to add :conditions to the declarations:

has_and_belongs_to_many :benched_players, :join_table => 'teams_players', :association_foreign_key => 'player_id', :class_name => 'Player', :conditions => { :benched => true }

(not sure if this is 100% of what you need, but you get the idea)

On the other hand, if a player really can only be on one team, you'll have a much better time if you switch back to a plain has_many. On the other hand, if you've got a situation where players *can* be on multiple teams, it's possible that they could be "benched" only on some of them; in that case, you'll want a "decorated join model", with has_many :through.

--Matt Jones

The attribute (Matt Jones calls it a “condition”) of being on the bench or not on the bench is a property of the player not the team.

A team does not belong to the players. Players make up the team.

Consider the deletion anomaly. If a Player is removed, does the team cease to exist?

However, If a team is removed, then none of the players can theoretically belong to that team.

That makes a lot of sense Ar. Thanks!

Hi Ar, Actually I realized this won't work because players can be on multiple teams and can be benched on one team but not the other. Therefore it can't be an attribute of the player, it has to be an attribute of the team. Looks like I'll have to go back to my old idea. -Frank

Frederick, That was the solution. Thanks! -Frank