Design question and opinions

I’m just working through the Agile web dev book (which is great) and i’m
at the point i’d like to put together something to test my
understanding. Luckily I have a project that will help my gaming
community organise games on modern warfare 2. It also doesn’t map onto
the depot like for like which is good :slight_smile:

The basic idea is you have a list of game modes and a list of maps.
These lists can be added to. They can’t be removed but they can be set
to inactive.

Now a game consists of a map and a game mode. A match consists of one or
more games (specified by the user). The games for a particular match get
chosen at random - the one rule being that the a map and game mode may
only appear once in the match.

The application should allow the user to enter the number of games they
want to play and generate a match. this match is given a short
description (e.g. Team 1 v Team 2) and gets stored so that people
playing the match can see what games they will be playing.

So far i’ve got the models i think i need:

  • map(s)
  • game_modes(s)
  • game(s)
  • match(s)
  • match_game(s)

I’ve created the map, game_model and match using scaffold as i want to
be able to maintain them through the UI.

I’ve created game and match_game as pure models as they are part of the
match creation.

So far, am i on the right track based on good practice and design?

One consideration i did have was whether, based on the fact that the
maps and game_modes tables will always have a relatively small number of
entries, i should just autogenerate the rows (20 in each table = 400
rows. random generate a number between 1 and 400 and it picks the game).
If i was to do this where would i embed the method to autopopulate the
game table? (in the game model itself or a helper - i’m not sure on best
practice). This could also be called if the admin decided to update the
table with a new entry (i.e. it would create the extra matches needed).

At this stage i haven’t even thought through how the actual UI will
build all the bits and put them together but i’m thinking this would be
the job of my match controller which creates a match object, x game
objects and sets the ‘games’ property of the match object before
committing the changes to the DB and letting rails do some magic to save
it all (i’m not looking for someone to tell me as i’d like to work it
out but if i’m way off track here then a pointer or 2 would be
appreciated).

Thanks for taking the time to read and i appreciate any comments or
opinions you can offer this newbie :slight_smile:

ooh found ‘has_many_and_belongs_to’ in ActiveRecord that takes care of
the match->match_game<-game relationship nicely!

The solution i think i’m going to go with is to pre-load the game table
and add some methods to the game model to return a game or games in the
various ways i’ll need them e.g.

get_random_game
get_random_active_game(exclude_these_games[])
get_all_active_games

My match controller can then use these as part of the logic that builds
the match before committing it to the db.

If someone updates the maps or game_modes models then i’ll trigger an
‘update_list_of_games’ on the Game class to populate any new game modes
as a result of the change.

Not sure what people feel about this but it seemed right in my head lol.

2010/1/15 Jon C. [email protected]:

ooh found ‘has_many_and_belongs_to’ in ActiveRecord that takes care of
the match->match_game<-game relationship nicely!

The convention is for the HABTM table name to be alpha ordered and
plural, so in this case it would be games_matches. Then you will not
have to explicitly name it using :through.

If you have not seen it already you may find the ActiveRecord
Associations guide at http://guides.rubyonrails.org/ useful. Also the
other guides there of course.

Colin

Jon C. wrote:

I’ve created the map, game_model and match using scaffold as i want to
be able to maintain them through the UI.

I’ve created game and match_game as pure models as they are part of the
match creation.

So far, am i on the right track based on good practice and design?

If you have written your Cucumber stories and/or RSpec examples before
all this work, using them to drive your design, then you are on the
right track to good practice and design.

One consideration i did have was whether, based on the fact that the
maps and game_modes tables will always have a relatively small number of
entries, i should just autogenerate the rows (20 in each table = 400
rows. random generate a number between 1 and 400 and it picks the game).
If i was to do this where would i embed the method to autopopulate the
game table? (in the game model itself or a helper - i’m not sure on best
practice). This could also be called if the admin decided to update the
table with a new entry (i.e. it would create the extra matches needed).

The latest version of Rails has a convention for this, and an associated
rake task. The feature is called “Seeds.” You’ll notice there will be a
db/seeds.rb file for putting your Ruby code to populate your seed data.
Then you can run rake db:seed after running rake db:migrate to execute
the data seeds.

At this stage i haven’t even thought through how the actual UI will
build all the bits and put them together but i’m thinking this would be
the job of my match controller which creates a match object, x game
objects and sets the ‘games’ property of the match object before
committing the changes to the DB and letting rails do some magic to save
it all (i’m not looking for someone to tell me as i’d like to work it
out but if i’m way off track here then a pointer or 2 would be
appreciated).

I would think that the controller would simply handled the request to
“create” a new game:

matches_controller.rb

def create
@match = Match.new
@match.start

Stuff to handle return the response

end

match.rb

class Match << ActiveRecord::Base

def start
# Do all the stuff you need to do to start a match
end

end

This is often referred to as “skinny controller, fat model design,” and
is typically promoted in Rails as a “best practice.”

Robert W. wrote:

Jon C. wrote:

ooh found ‘has_many_and_belongs_to’ in ActiveRecord that takes care of
the match->match_game<-game relationship nicely!

The current trend in Rails is toward has_many :through instead of
has_and_belongs_to_many (HABTM).

Says who? I tend to start with HABTM and refactor to has_many :through
if necessary.

The has_many :trough is more flexible,
and often more RESTful.

More flexible, yes. But it’s not the Simplest Thing That Could Possibly
Work [TM] in this case.

HABTM is a special simplified case. If your data fits the special case,
it makes sense to take advantage of it.

As for REST, that’s a routing issue, not an associations issue.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Jon C. wrote:

ooh found ‘has_many_and_belongs_to’ in ActiveRecord that takes care of
the match->match_game<-game relationship nicely!

The current trend in Rails is toward has_many :through instead of
has_and_belongs_to_many (HABTM). The has_many :trough is more flexible,
and often more RESTful.

Imagine what happens if you need to store something that relates to a
particular game of a match. You can’t store that in either the matches
nor the games tables. You would instead need access to the joining table
match_games.

class Match << ActiveRecord::Base
has_many :match_games
has_many :games, :through => :match_games
end

class Game << ActiveRecord::Base
has_many :match_games
has_many :matches, :though => :match_games
end

class MatchGame << ActiveRecord::Base
belongs_to :match
belongs_to :game
end

Again write your stories and use them to drive your design. This is
opposed to trying to build your application from the perspective of the
data model. Letting your acceptance criteria drive your design will
develop into a better user experience. You’ll be concentrating on what
the user sees, and how they interact with your application. I think
you’ll find that the model almost takes care of itself as you write code
to make your stories (and specs) pass.

Feature: player starts a new match
As a player
I want to start a new match
So that I can have fun fragging my friends

Scenario: starting a match
Given a new match
When I start the match
Then I should <fill in what you expect to see (or happen)>
And I should

Scenario:
Given …
When …
Then …

Marnen Laibow-Koser wrote:

Robert W. wrote:

Jon C. wrote:

ooh found ‘has_many_and_belongs_to’ in ActiveRecord that takes care of
the match->match_game<-game relationship nicely!

The current trend in Rails is toward has_many :through instead of
has_and_belongs_to_many (HABTM).

Says who? I tend to start with HABTM and refactor to has_many :through
if necessary.

Says, DHH in his initial promotion of the decision to move to a RESTful
design. I did not, however, say that that this was right, just that it
has been proposed by the person who developed the idea.

The has_many :trough is more flexible,
and often more RESTful.

More flexible, yes. But it’s not the Simplest Thing That Could Possibly
Work [TM] in this case.

I concede this point.

HABTM is a special simplified case. If your data fits the special case,
it makes sense to take advantage of it.

As for REST, that’s a routing issue, not an associations issue.

Again I concede. But, this was just a misuse of the terminology. I meant
to say that having the joining model can lead to more RESTful routes in
many cases. Again this was another point in DHH’s initial talk on the
move to REST. At that time, however, all this REST stuff was
experimental. I’m sure we’ve learned a lot since that initial
presentation on the subject matter.

Robert W. wrote:

If you have written your Cucumber stories and/or RSpec examples before
all this work, using them to drive your design, then you are on the
right track to good practice and design.

Thats great advice and was on my list of ‘when i’ve got the basics down
i need to go and learn about…’ list. Sounds like I should probably
make it a priority. the later examples you gavce helped reinforce this
for me.

The current trend in Rails is toward has_many :through instead of
has_and_belongs_to_many (HABTM). The has_many :trough is more flexible,
and often more RESTful.

I did pick up on this during some reading i did this morning (Colin’s
suggestion to read the ActiveRecord Associations guide helped me better
understand). As this is a very simple system that i have no plans to
extend (famous last words hehe) i felt HABTM fitted the bill.

The latest version of Rails has a convention for this, and an associated
rake task. The feature is called “Seeds.” You’ll notice there will be a
db/seeds.rb file for putting your Ruby code to populate your seed data.
Then you can run rake db:seed after running rake db:migrate to execute
the data seeds.

Brilliant! Thank you for the pointer.

This is often referred to as “skinny controller, fat model design,” and
is typically promoted in Rails as a “best practice.”

aha (penny starting to drop here)

Thanks for taking the time to read this and i really appreciate all the
responses and advice.