问题
I have this User and team model which has the following association:
user.rb
class User < ActiveRecord::Base
belongs_to :team
team.rb
class Team < ActiveRecord::Base
has_many :users
has_one :leader, class_name: "User", foreign_key: "leader_id"
belongs_to :manager, class_name: "User", foreign_key: "manager_id"
but it seems that I can't imagine representing it properly into a migration. At first, this is what I did:
class AddTeamIdToUsers < ActiveRecord::Migration
def change
add_column :users, :team_id, :integer
add_index :users, :team_id
end
end
class AddUsersToTeams < ActiveRecord::Migration
def change
add_reference :teams, :leader, index: true
add_reference :teams, :manager, index: true
end
end
for sure, what I did on AddTeamToIdUsers
was a many-to-one association since a Team
can have many Users
, but the leader position should only be exclusive for a specific team only (same goes to members as well, they should not belong to other teams). Managers, however, can have many teams to manage. Going back to my concern, how can I represent my scenario into a migration? Or are there any adjustments I should make in my associations? After the necessary adjustments and solutions considered, will the application automatically follow the association rules upon adding/updating teams?
回答1:
Because a manager can have multiple teams, but is still "part of" the team, I'd suggest creating a join table for users
and teams
. We'll call it members
. It will reference both user
and team
.
class CreateMembers < ActiveRecord::Migration
def change
create_table :members do |t|
t.references :user
t.references :team
t.timestamps
end
end
end
Then, we'll need add the members
association to the User
model. Users will have many members, and, because of managers, have many teams as well. I've also included a function to get the team of a worker or leader, since there's only one.
class User < ActiveRecord::Base
has_many :members
has_many :teams, through: members, dependent: destroy
validates_associated :members # More on this later
# for workers and leaders
def team
self.teams.first
end
end
Similar to the User
model, we'll need to add the members
association to the Team
model. We'll also include a few functions to get the leader and manager of a team, and validation to make sure a team has exactly one leader and one manager.
class Team < ActiveRecord::Base
has_many :members
has_many :users, through: :members, dependent: destroy
validate :has_one_leader_and_manager
validates_associated :members # More on this later
def manager
self.users.where(type: 'manager').first
end
def leader
self.users.where(type: 'leader').first
end
def has_one_leader_and_manager
['leader', 'manager'].each do |type|
unless self.users.where(type: type).count == 1
errors.add(:users, "need to have exactly one #{type}")
end
end
end
end
Lastly, we'll set up the Member
model. We can also include some validation to ensure that a team can only have one leader and one manager, and that workers and leader cannot belong to more than one team.
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :team
validate :team_has_one_leader_and_manager
# Make sure player (worker or leader) is only on one team
validates :user_id, uniqueness: true, if: :is_player?
def is_player?
['worker', 'leader'].include? user.type
end
def team_has_one_leader_and_manager
if ['leader', 'manager'].include?(user.type)
if team.users.where('type = ? AND id != ?' user.type, user_id).count.any?
errors.add(:team, "can't add another #{user.type}")
end
end
end
end
Note that with the validation methods, you may want to move them around and/or refactor them, depending on how you add users and team, and how you'll add new members. However, this answer will hopefully give you enough information to get started.
回答2:
Your migrations look correct, but your associations are not complete:
class User < ActiveRecord::Base
belongs_to :team
has_one :leading_team, class_name: 'Team', foreign_key: 'leader_id'
has_many :managed_teams, class_name: 'Team', foreign_key, 'manager_id'
class Team < ActiveRecord::Base
has_many :users
belongs_to :leader, class_name: "User"
belongs_to :manager, class_name: "User"
And you should be all set.
来源:https://stackoverflow.com/questions/24289861/association-and-migration-between-users-and-teams-rails