trying to refactor code to provide clean association
A GAME has a HOME_TEAM and an AWAY_TEAM
A TEAM has many GAMES as a HOME_TEAM or an AWAY_TEAM
Association between GAME and TEAM is a straight-forward HABTM BUT I need to denote which of the two TEAMS associated with a GAME is the HOME_TEAM and which is the AWAY_TEAM. I did it by adding extra fields and associations but this is obvious very wet rather than dry. I know the answer is in through but I seem to have had a brain meltdown and can't quite get my head round this.
Basically I want to be able to do Game.teams (returns collection of both teams) and Game.home_team (get and set a TEAM to home_team) and Game.away_team (get and set a TEAM to away_team)
Sorry to pose such a straightforward sounding query but it's just got away from me
class Game < ActiveRecord::Base
belongs_to :home_team
belongs_to :away_team
has_and_belongs_to_many :teams
end
class HomeTeam < ActiveRecord::Base
belongs_to :team
has_one :games
end
class AwayTeam < ActiveRecord::Base
belongs_to :team
has_one :games
end
class Team < ActiveRecord::Base
has_and_belongs_to_many :games
has_many :away_teams
has_many :home_teams
end
All help greatly appreciated
Peter
To do what you want to do, you should use a has_many :through
instead of hatbm
. See here for more info. In short, the good thing is that you can add other variables to the joins table. In your case, a boolean called home_team.
So here's what I'd do. First, create an association table (since I don't have much imagination, I'll call it participation):
create_table :participations, do |t|
t.integer :game_id, :null => false
t.integer :team_id, :null => false
t.boolean :home_team
end
As you can see, unlike your gamesteams table, this one has an id. And you can add attributes to it. Then, I would use these models:
class Participation < ActiveRecord::Base
belongs_to :game
belongs_to :team
end
class Game < ActiveRecord::Base
has_many :participations, :dependent => :destroy
has_many :teams, :through => :participations
end
class Team < ActiveRecord::Base
has_many :participations, :dependent => :destroy
has_many :games, :through => :participations
end
So to get the teams of a game, you do @game.teams
.
Now, to get home_team and away_team, add these methods to your Game model:
def home_team
self.teams.joins(:participations).where("participations.home_team IS ?", true).first
end
def away_team
self.teams.joins(:participations).where("participations.home_team IS ?", false).first
end
And then you'll be able to do @game.home_team
and @game.away_team
.
Peter's edit: Ok, so for mysql you'll have to use different where statements:
self.teams.joins(:participants).where("participants.home_team = ?", true).first self.teams.joins(:participants).where("participants.home_team IS NULL").first
I can either use " = ?", true and "!= ?", true --OR-- IS NOT NULL and IS NULL
I think for false you should try using where("participants.home_team = ?", false)
Ok, so so there are at least 2 ways to set up your teams.
If you go for number 1, you should use a radio button to let the user decide. Something like this:
<%= label_tag :home, 'Home Team' %><br />
<%= label_tag :home_team_1, 'Team 1' %><%= radio_button_tag :home_team, 1 %>
<%= label_tag :home_team_2, 'Team 2' %><%= radio_button_tag :home_team, 2 %>
So if params[:home_team] == 1
, the first team is the home team, if params[:home_team] == 2
, the second team is the home team.
If you go for number 2, then, you should have something like this in your form do add the teams to your game:
<%= label_tag :name, 'Home Team' %>
<%= text_field_tag :name, nil, :name => "home[]" %>
<%= label_tag :name, 'Away Team' %>
<%= text_field_tag :name, nil, :name => "away[]" %>
So then in your controller you can do something like
@game = Game.new(params[:game])
home = Team.create(params[:home])
# or
home = Team.find_or_create_by_name(params[:home][:name])
@game.participations.create(:team_id => home.id, :home_team => true or 1)
away = Team.find_or_create_by_name(params[:away][:name])
@game.participations.create(:team_id => away.id, :home_team => false or 0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With