HABTM and Fixtures

First off, I've done some googling and read some very informative
stuff, but I'm having an issue and I can't figure out what I'm doing
wrong. I've got it working with one model, but the other one is
choking.. Here's the relevant data (and my current stuff):

player.rb:
class Player < ActiveRecord::Base
  has_and_belongs_to_many :friends,
    :class_name => "Player", :association_foreign_key =>
"friend_id", :join_table => "friends_players"

  has_and_belongs_to_many :leagues,
    :class_name =>
"Player", :association_foreign_key=>"player_id", :join_table=>"players_leagues"
end

complex setup, but let me try to sort it out a bit:

player.rb: (the friends thing has nothing to do with the problem, so i
don't include it)

has_and_belongs_to_many :leagues

that's default stuff, so no need to include it, makes code less
readable:
:class_name => "Player"
:association_foreign_key=>"player_id",
:join_table=>"players_leagues"

league.rb:
has_many :players,
    :class_name => "Player", :association_foreign_key =>
"player_id", :join_table => "players_leagues"

if i get your setup right, the wrong thing here is the has_many
it should be habtm as in players

has_and_belongs_to_many :players

again the rest of definition isn't necessary, since you keep with naming
conventions.

leagues.yml:
league1:
  player_id: user1 <= ??? why that ???
  players: user1, user2, user3

is there another player_id in leagues? if so, define it as:
belongs_to :players
otherwise kick that line

i hope i understood you setup, otherwise it may be helpful to
have a few more details of the associations and the exact fieldnames in
all three used tables

Thanks Thorsten. :slight_smile:

Well the reason that league has a player_id is that is the "owner" of
the league. He's by default a player in the league as well. Right now
that's the last problem.. I had to create leagues_players (I guess
players_leagues isn't the convention) and modified league and player
to these:

class League < ActiveRecord::Base
  has_and_belongs_to_many :players
    #:class_name => "Player", :association_foreign_key =>
"player_id", :join_table => "players_leagues"
end

class Player < ActiveRecord::Base
  has_and_belongs_to_many :friends
   # :class_name => "Player", :association_foreign_key =>
"friend_id", :join_table => "friends_players"

  has_and_belongs_to_many :leagues
end

leagues.yml is currently

league1:
  name: Test League
  player_id: user1
  playercount: 8
  players: user1, user2, user3

now the rake task runs without error, and I get players being inserted
in leagues_players correctly. However the player_id is not set (the
owner of the league).

ok, so we have the complicated part.
for the owner just define the association as well:

player.rb:

has_one :league

league.rb:
belongs_to :player

in this case i would go for renaming this like
belongs_to :owner, :foreign_key => player_id
this will make you code more readable later on
since you'll acces your league like

@league.players
and
@league.player

which can be confusing so the combination
@league.players
@league.owner
would work better

Thanks again Thorsten, some more frustration on my end though. Adding
the "belongs_to" has broken the friends association, somehow.

class League < ActiveRecord::Base
  has_and_belongs_to_many :players
    #:class_name => "Player", :association_foreign_key =>
"player_id", :join_table => "players_leagues"

  belongs_to :owner, :foreign_key => :player_id
end

class Player < ActiveRecord::Base
  has_and_belongs_to_many :friends
  # :class_name => "Player", :association_foreign_key =>
"friend_id", :join_table => "friends_players"

  # If I comment this line out, it doesn't complain, but the leagues
owner id (player_id) doesn't get set
  # if I uncomment it, I get an error.
  #has_many :leagues, :foreign_key=> player_id
end

The error I get is:
rake aborted!
Mysql::Error: #42S22Unknown column 'friends' in 'field list': INSERT
INTO `players` (`name`, `network_id`, `friends`) VALUES ('Jason',
'dbg_12345', 'user2, user3')

For further reference, the schema

  create_table "friends_players", :id => false, :force => true do |t|
    t.integer "player_id"
    t.integer "friend_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "friends_players", ["friend_id"], :name =>
"index_friends_players_on_friend_id"
  add_index "friends_players", ["player_id"], :name =>
"index_friends_players_on_player_id"

  create_table "leagues", :force => true do |t|
    t.string "name"
    t.integer "playercount"
    t.integer "player_id"
    t.datetime "timestarted"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "leagues_players", :id => false, :force => true do |t|
    t.integer "league_id"
    t.integer "player_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "leagues_players", ["league_id"], :name =>
"index_leagues_players_on_league_id"
  add_index "leagues_players", ["player_id"], :name =>
"index_leagues_players_on_player_id"

  create_table "players", :force => true do |t|
    t.string "name"
    t.string "network_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

To followup my own message, I had to simplify a bit to get it working

class League < ActiveRecord::Base
  has_and_belongs_to_many :players

  belongs_to :player # trying to do :owner, :foreign_key here caused
an error in the parse
end

class Player < ActiveRecord::Base
  has_and_belongs_to_many :friends

  has_many :leagues
end

league1:
  name: Test League
  player: user1 < -- Had to change to player instead of player_id
  playercount: 8
  players: user1, user2, user3

Thanks a lot for all of your help Thorsten.

Based on what I understand of your requirements, this doesn't seem quite right.

Players don't have many leagues, each player belongs to one league,
and may have at most one league (as it's owner). Those are two
separate relationships, so should be modeled separately.

I think you want something like:

class League < ActiveRecord::Base
   has_many :players
   belongs_to :owner, :class_name => 'Player'
   # this implies that the 'leagues' table has an owner_id field
end

class Player < ActiveRecord::Base
   belongs_to :league
   has_one :owned_league, :class_name => 'League', :foreign_key => :owner_id

end

leagues.yml

league1:
    name: TestLeague
    owner: player1a
league

league2:
    name: TestLeague2
    owner: player2a

players.yml
   player1a:
        league: league1
   player1b:
        league: league1
   player1c:
       league: league1
  player2a:
      league: league2
  player2b:
      league: league2
...

Of course the player names can be whatever you want, I picked player1a
etc. just to make the relelationships clear

Ya, the difference was that players (human players, not the members of
the team) can own multiple leagues and play in mulitple leagues.