我有这个用户和团队模型,它具有以下关联:
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"
但似乎我无法想象将其正确地表示为迁移。起初,这就是我所做的:
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
当然,我在AddTeamToIdUsers
上所做的是多对一关联,因为Team
可以有很多Users
,但领导者位置应仅仅限特定团队(同样适用于成员,他们不应属于其他团队)。但是,经理可以让很多团队进行管理。回到我关心的问题,我如何将我的场景表示为一个迁移?或者我应该在协会中做出任何调整?在考虑了必要的调整和解决方案后,应用程序会在添加/更新团队时自动遵循关联规则吗?
答案 0 :(得分:3)
您的迁移看起来正确,但您的关联不完整:
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"
你应该全力以赴。
答案 1 :(得分:2)
由于经理可以拥有多个团队,但仍然是团队的“成员”,因此我建议您为users
和teams
创建一个联接表。我们称之为members
。它将引用user
和team
。
class CreateMembers < ActiveRecord::Migration
def change
create_table :members do |t|
t.references :user
t.references :team
t.timestamps
end
end
end
然后,我们需要将members
关联添加到User
模型。用户将拥有许多成员,并且由于经理,也有许多团队。我还包括一个函数来获得一个工人或领导者的团队,因为只有一个。
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
与User
模型类似,我们需要将members
关联添加到Team
模型。我们还将包括一些功能,以获得团队的领导者和经理,并进行验证以确保团队中只有一名领导者和一名经理。
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
最后,我们将设置Member
模型。我们还可以包括一些验证,以确保团队只能拥有一名领导者和一名经理,并且工作人员和领导者不能属于多个团队。
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
请注意,使用验证方法,您可能希望移动它们和/或重构它们,具体取决于您添加用户和团队的方式以及如何添加新成员。但是,这个答案有望为您提供足够的信息来开始。