Rails Model user adding player to user pinboard

2019-09-04 11:53发布

问题:

I'm creating a sports application which allows users to create pinboards, as many as they like. The users can then add say their favorite player to a specified pinboard. So for example User: Jack, creates a new pinboard called "My favorite defenders", He can then go and find his favorite defenders, say Kevin Garnet, and add/pin garnet to his "My favorite defenders" Pinboard.

I have a Users model, a Pinboards Model and a Players model. I tried the following association but didn't work as I wanted.

User

has_many :pinboards
has_many :pins, through: pinboards, source: :player

Pinboard

belongs_to :user
belongs_to :player

I know a player can't have many pinboards and a pinboard will hold many players. How can I get the behavior i want; User creates pinboard---user adds player to pinboard.

回答1:

User

has_many :pin_boards
has_many :pins, through: :pin_boards, source: :players


PinBoard

belongs_to :user
has_many :pin_board_player_assignments
has_many :players, through: :pin_board_player_assignments


PinBoardPlayerAssignment

belongs_to :pin_board
belongs_to :player


Player

has_many :pin_board_player_assignments
has_many :pin_boards, through: :pin_board_player_assignments

So, basically, you'll need to add another model called PinBoardPlayerAssignment. From there, I'd highly recommend using this join model to create and manage the assignments, like so:

PinBoardPlayerAssignment

def self.create_between(a_pin_board, a_player)
  assignment = a_pin_board.pin_board_player_assignments.build
  assignment.player = a_player
  assignment.save!
end

This way, you can use instance methods on PinBoard or on Player to DRYly create the assignment between the PinBoard and the Player. Basically, let the object that knows the most about pin_boards and players be the one to manage the relationships between them.

PinBoard

def add_player(a_player)
  PinBoardPlayerAssignment.create_between(self, a_player)
end


Player

def add_to_pin_board(a_pin_board)
  PinBoardPlayerAssignment.create_between(a_pin_board, self)
end

And the great thing is that Rails 3.2+ allows nested :through relationships so your original request -- to have @user.pins should compile the result of going through the pin_board and then through the pin_board_player_assignment table automatically.



回答2:

Try:

has_many :pins, through: :pin_boards, source: :players

The key is to make the source be the exact same as the relationship in the join model. So, since your join model (PinBoard) almost certainly says has_many :players then you have to match that word players exactly. So you were just missing the 's'.