Topic: Modelling decision - newbie help required

Hi all,

This is my first post and I'm a newbie to Rails and OOP in general - so please bear with me.

My problem is (as I see it) all about deciding which way to model/associate my db/tables, I have the following tables:

Player
-id
-name

Game
-id
-gamename
-player_id

Scenario
-id
-scenarioname
-game_id

battle
-id
-player1 (player_id)
-player2 (player_id)
-gameplayed (game_id)


I have tried to visualise my associations using the following:

note1: this is just a notepad file I've used and not genuine code
note2: The left column is my understanding of the relationship - the right column is Rails speak.


From a players' perspective

A player has many games            # has_many :games
A player has many battles        # has_many :battles

From a games' perspective

A game has a single owner (player)    # belongs_to :player
A game has many scenarios        # has_many :scenarios
A game has many battles            # has_many :battles

From a scenarios' perspective

A scenario belongs to a game        # belongs_to :game
A scenario belongs to a battle        # belongs_to :battle

From a battles' perspective

A battle has one game            # belongs_to :game
A battle has many players/winner    # has_many :players
A battle has one scenario        # belongs_to :scenario


Can someone confirm:

1. That I have identified the associations correctly on both sides of the relationship
2. Am I missing something with these associations?

Any help and/or constructive comments are gratefully appreciated.

Thanks,

Steve.

Re: Modelling decision - newbie help required

You are almost there, just a few things:

There's no foreign-key linking scenario and battle in the database. I'm assuming you want scenario_id column in the battles table? After that, the Scenario should has_one/has_many :battle(s).

The other problem is with how a player relates to battle/game. Having two player foreign-keys in battles table is a decent solution. However, this will make it difficult to fetch all battles/games for a given player. A player cannot simply has_many :games/battles. An alternative solution is to create another join table/model. You can use a position column to determine wether the player is first or second. You may want to add validation to restrict two players to a given battle. Here's some code.

# players
# - id
# - name
class Player < ActiveRecord::Base
  has_many :participations
  has_many :battles, :through => :participations
  has_many :games, :through => :battles # not sure if this will work
  has_many :games_as_owner, :class_name => 'Games'
end

# games
# - id
# - name
# - player_id
class Game < ActiveRecord::Base
  belongs_to :player
  has_many :scenarios
  has_many :battles
  has_many :participations, :through => :battles
  has_many :players, :through => :participations # again, not sure if this will work
end

# scenarios
# - id
# - name
# - game_id
class Scenario < ActiveRecord::Base
  belongs_to :game
  has_many :battles # you may want has_one
end

# battles
# - id
# - game_id
# - scenario_id
class Battle < ActiveRecord::Base
  belongs_to :game
  belongs_to :scenario
  has_many :participations
  has_many :players, :through => :participations
end

# participations
# - id
# - battle_id
# - player_id
# - position
class Participation < ActiveRecord::Base
  belongs_to :battle
  belongs_to :player
 
  acts_as_list :scope => 'battle_id'
 
  def validate
    errors.add('position', 'cannot have more than 2 players') if position > 2
  end
end


If you would prefer to stick with your old schema (no participations table) it is still possible to fetch the games/battles for a given player, but you will need to use some custom SQL (I think anyway).

Last edited by ryanb (2007-01-09 12:13:40)

Railscasts - Free Ruby on Rails Screencasts

Re: Modelling decision - newbie help required

Quick reply: Thanks for the response & the code is a bonus - for me :-). I'll look into this in the next couple of days.

Thanks,

Steve.

Re: Modelling decision - newbie help required

Ryan,

Thank you for the help/code you supplied, I've spent the last several days working my way through this and I think the "penny" is starting to drop for me :-) In other words I'm starting to understand the importance of getting your relationships in order to allow for smoother operation of the code.

Thanks - Steve.

Re: Modelling decision - newbie help required

At this point I have a "fully working" application - in terms of all CRUD aspects (i.e. I have replaced all scaffolding options) for all models except one!

I am struggling with one coding issue. This is when I create a battle how do I go about writing multiple records to the participations table?

I am also struggling with "acts_as_list", I understand the words but I don't understand why/how I would use this function.

Once again thanks in advance for any help you can supply,

Steve.

FYI: my models are:

class Battle < ActiveRecord::Base
  has_many :players, :through => :participations
  belongs_to :scenario
  belongs_to :game
  has_many :armies
  has_many :participations
 
end

class Player < ActiveRecord::Base
  has_many :games
  has_many :battles, :through => :participations
end

class Participations < ActiveRecord::Base
belongs_to :battle
belongs_to :player

end

Re: Modelling decision - newbie help required

devonps wrote:

I am struggling with one coding issue. This is when I create a battle how do I go about writing multiple records to the participations table?

It depends largely on how you want the interface to behave. The easiest way is to first create a battle, then in the battle show page have an "add player" link. This can take you to a Participation create action where you select the player to add to the battle. Upon submitting this form a new participation is added to the battle linking to the selected player. I can give you some code if you want.


devonps wrote:

I am also struggling with "acts_as_list", I understand the words but I don't understand why/how I would use this function.

I just added acts_as_list so the "position" column will be set automatically. In other words, the first player you add to the battle will automatically have position "1", the second player will have position "2", etc. There's even some cool javascript/ajax recipes out there to help you do drag and drop sorting.

Railscasts - Free Ruby on Rails Screencasts

Re: Modelling decision - newbie help required

I have implemented the "easy" solution - of providing a link to another form, etc - this is working, ie the join table is updating correctly with the player_id + battle_id.

What I would like to do now is, depending on a field (players_assigned) in the battles table I would like to display different HTML. I have attempted to implement the case statement - from within the view - but cannot get the syntax correct and have had no luck with my searches. I know I should remove this logic from the view, but I want a working appl. first then I can re-organise the logic accordingly.

To visualise:

when players_assigned = 0
the link "Please assign players" is generated

when players_assigned = 1
<td><%player1%></td>  is visible
<td>link "assign player"</td> is visible

when players_assigned = 2
<td><%player1%></td> is visible
<td><%player2%></td> is visible

Hope that makes things clear?