用户和团队之间的关联和迁移(rails)

时间:2014-06-18 15:45:58

标签: ruby-on-rails ruby activerecord associations rails-migrations

我有这个用户和团队模型,它具有以下关联:

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,但领导者位置应仅仅限特定团队(同样适用于成员,他们不应属于其他团队)。但是,经理可以让很多团队进行管理。回到我关心的问题,我如何将我的场景表示为一个迁移?或者我应该在协会中做出任何调整?在考虑了必要的调整和解决方案后,应用程序会在添加/更新团队时自动遵循关联规则吗?

2 个答案:

答案 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)

由于经理可以拥有多个团队,但仍然是团队的“成员”,因此我建议您为usersteams创建一个联接表。我们称之为members。它将引用userteam

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

请注意,使用验证方法,您可能希望移动它们和/或重构它们,具体取决于您添加用户和团队的方式以及如何添加新成员。但是,这个答案有望为您提供足够的信息来开始。