Reputation: 51
I have an app with Two Models Stadium & Team, they have a many-to-many relationship and are joined in the middle by a join table.
My current structure looks like this:
class Team < ActiveRecord::Base
has_many :stadiumteams, :class_name => 'StadiumTeam'
has_many :stadiums, :through => :stadiumteams
end
class Stadium < ActiveRecord::Base
has_many :stadiumteams, :class_name => 'StadiumTeam'
has_many :teams, :through => :stadiumteams
end
class StadiumTeam < ActiveRecord::Base
belongs_to :stadium
belongs_to :team
end
This relationship show “current residents for a stadium”. But now I also want to have a relationship that can display old residents.
For example Tottenham (Team) used to play at White Hart Lane (Stadium) But now play at (Wembley) Stadium.
I am planning to do the following. But I am unsure if this will work or if there is a better way to do it?
Team
class Team < ActiveRecord::Base
has_many :stadiumteams, :class_name => 'StadiumTeam'
has_many :stadiums, :through => :stadiumteams
#has_many :oldstadiums, :class_name => 'OldStadium'
#has_many :stadiums, :through => :oldstadiums
end
Stadium
class Stadium < ActiveRecord::Base
has_many :stadiumteams, :class_name => 'StadiumTeam'
has_many :teams, :through => :stadiumteams
#has_many :oldstadiums, :class_name => 'OldStadium'
#has_many :teams, :through => :oldstadiums
end
New Join Table
class OldStadium < ActiveRecord::Base
belongs_to :stadium
belongs_to :team
end
Any help is very appreciated!
EDIT: (Input fields) Here's how the code for my inputs currently looks:
<%= f.association :teams, label: 'Current Residents', class:'select2-field', placeholder: "Select teams", collection: @teams, input_html: { multiple: true }, hint: 'Select one or multiple teams.'%>
<%= f.association :teams, label: 'Old Residents', class:'select2-field', placeholder: "Select teams", collection: @teams, input_html: { multiple: true }, hint: 'Select one or multiple teams.' %>
And my params
def stadium_params
params.require(:stadium).permit(:name, :capacity, :city, :country, :location_name, :address, :longitude, :latitude, :image, :surface, :official_opening_date, :cost, :web_url, :also_known_as, :record_attendance, :team_ids => [])
end
Upvotes: 1
Views: 1300
Reputation: 54902
You can define relations with a lambda to append an additional where
clause in the relation:
class Team < ActiveRecord::Base
has_many :stadiumteams, :class_name => 'StadiumTeam'
has_many stadiums, :through => :stadiumteams
has_many :current_stadiums, ->{ where(stadiumteams: { current_home: true }) }, :through => :stadiumteams, :class_name => 'Stadium', :source => :stadium
has_many :previous_stadiums, ->{ where(stadiumteams: { current_home: false }) }, :through => :stadiumteams, :class_name =>'Stadium', :source => :stadium
end
class Stadium < ActiveRecord::Base
has_many :stadiumteams, :class_name => 'StadiumTeam'
has_many :teams, :through => :stadiumteams
has_many :current_teams, ->{ where(stadiumteams: { current_home: true }) }, :through => :stadiumteams, :class_name => 'Team', :source => :team
has_many :previous_teams, ->{ where(stadiumteams: { current_home: false }) }, :through => :stadiumteams, :class_name =>'Team'. :source => :team
end
class StadiumTeam < ActiveRecord::Base
belongs_to :stadium
belongs_to :team
end
And then you should be able to do (in rails console):
team = Team.first
stadium = Stadium.first
team.previous_stadiums <<
team.save
team.reload.previous_stadiums.include?(stadium)
# => should return true
So this way you can simply use in your UI a input for the association :previous_teams
and :current_teams
:
f.association :current_teams, #...
Upvotes: 1
Reputation: 957
There are several ways to fulfill your requirement. Your approach also enough, but for efficiency, since the number of Stadium is small ( thousands ), you can use STI for Stadium
entity.
class Stadium < ActiveRecord::
has_many :stadiums_teams
has_many :teams, through: :stadiums_teams
end
class OldStadium < Stadium; end
class RecentStadium < Stadium; end
class StadiumTeam < ActiveRecord::Base
belongs_to :stadium
belongs_to :team
end
class Team < ActiveRecord::Base
has_many :stadiums_teams
has_many :stadiums, through: :stadiums_teams, source: :stadium
has_many :old_stadiums, through: :stadiums_teams,
source: :stadium, class_name: OldStadium.name
has_many :recent_stadiums, through: :stadiums_teams,
source: :stadium, class_name: RecentStadium.name
end
So, in most case, you will work with OldStadium
/ RecentStadium
model, but when you want to check if a team ever played at a specific stadium or not, just use Stadium
model.
Upvotes: 1