Reputation: 6136
I have two models in my rails 4.2.4 project that I'd like to join together and I'm struggling with creating the correct relationship between the two. The domain in question is rugby and the code is all available at https://github.com/rgbycch/rgbycch-rest/tree/rails. The models are:
Player
(https://github.com/rgbycch/rgbycch-rest/blob/rails/app/models/player.rb)
PlayerPosition
(https://github.com/rgbycch/rgbycch-rest/blob/rails/app/models/player_position.rb)
I'd like to be able to create a relationship whereby a Player
can have multiple favoured PlayingPosition
s. I believe my db structure would need to look something like this:
create_table :favoured_positions do |t|
t.references :player, index: true, foreign_key: true # fk to player table
t.references :player_position, index: true, foreign_key: true # fk to player_position table
t.integer :num_favs # additional data for a favored playing position
t.timestamps null: false
end
I can generate a new FavoredPosition
model like this I guess:
bundle exec bin/rails generate model FavouredPosition player:references player_position:references num_favs:integer
which generates a class that looks like:
class FavouredPosition < ActiveRecord::Base
belongs_to :player
belongs_to :player_position
end
I'm not sure how to alter my Player
and PlayerPosition
models to reflect this new relationship. Is the following correct:
class Player < ActiveRecord::Base
has_many :favored_positions, :through => :favoured_positions
end
class PlayerPositions < ActiveRecord::Base
has_many :favored_playing_positions, :through => :favoured_positions
end
Would you advise me to add indexes to either of these tables too?
Thanks,
Sean
Upvotes: 1
Views: 54
Reputation: 5802
You would need to set up the associations like this:
class Player < ActiveRecord::Base
has_many :favoured_positions
has_many :player_positions, through: :favoured_positions
end
class PlayerPosition < ActiveRecord::Base
has_many :favoured_positions
has_many :players, through: :favoured_positions
end
See: http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Upvotes: 2
Reputation: 76784
Firstly, change PlayerPosition
to Position
, it's far simpler and works with the DRY (Don't Repeat Yourself) principle.
Secondly, what you're referring to is an ActiveRecord association. These are basically how the ActiveRecord ORM allows you to associate objects in Rails.
--
The association I feel you'd best using is either going to be has_many :through
or has_and_belongs_to_many
. Since you've comitted to has_many :through
, here's what you need to do:
#app/models/player.rb
class Player < ActiveRecord::Base
#columns id | etc | etc | created_at | updated_at
has_many :favoured_positions
has_many :positions, through: :favoured_positions
end
#app/models/position.rb
class Position < ActiveRecord::Base
#columns id | etc | etc | created_at | updated_at
has_many :favoured_positions
has_many :players, through: :favoured_positions
end
#app/models/favoured_position.rb
class FavouredPosition < ActiveRecord::Base
#columns id | position_id | player_id | any | other | column | created_at | updated_at
belongs_to :position
belongs_to :player
end
--
An important caveat about the difference between has_many :through
and has_and_belongs_to_many
. If you didn't have any extra columns in your favoured_positions
join model, I would recommend you use has_and_belongs_to_many
. It's far simpler for what you need:
#app/models/player.rb
class Player < ActiveRecord::Base
has_and_belongs_to_many :positions
end
#app/models/position.rb
class Position < ActiveRecord::Base
has_and_belongs_to_many :players
end
You'd then make a join table as follows:
#players_positions
player_id | position_id
Upvotes: 1