【问题标题】:has_many :through multiple joins tablehas_many :通过多个连接表
【发布时间】:2017-06-10 09:43:56
【问题描述】:

我正在尝试创建一个 4 路连接表。

class User < ApplicationRecord
  has_many :user_configurations
  has_many :teams, through: :user_configurations
  has_many :companies, through: :user_configurations

  scope :supervisors, -> { joins(:user_configurations).where(user_configurations: { supervisor: true }) }
  scope :agents, -> { joins(:user_configurations).where(user_configurations: { supervisor: false }) }
end

class Team < ApplicationRecord
  has_many :user_configurations
  has_many :users, through: :user_configurations
  belongs_to :company_unit
end

class CompanyUnit < ApplicationRecord
  has_many :user_configurations
  has_many :users, through: :user_configurations
  has_many :teams
  belongs_to :company
end

class Company < ApplicationRecord
  has_many :user_configurations
  has_many :users, through: :user_configurations
  has_many :company_units
  has_many :teams, through: :company_units
end

class UserConfiguration < ApplicationRecord
  belongs_to :user, optional: true
  belongs_to :team, optional: true
  belongs_to :company, optional: true
  #supervisor:boolean in this table
end

当我创建时,我会在 UserConfiguration 表中获得 2 个单独的条目。

Company.first.users.create(team_ids: [1])

id: 1, user_id: 1, team_id: nil, company_id: 1

id: 2, user_id: 1, team_id: 1, company_id: nil

我不知道尝试这样的事情是否是一种好习惯,任何建议都会非常有帮助,谢谢。每次搜索都会尝试执行 sql join 来查询数据。

编辑:决定不这样做,并将尝试找出不同的方法。

【问题讨论】:

  • 你的例子的商业模式是什么?因为你的模型看起来很混乱!
  • 我添加了公司团队关系。我希望能够让用户属于团队和公司,以便我可以删除用户团队但仍将其链接到公司。

标签: mysql ruby-on-rails ruby has-many-through


【解决方案1】:

我会改为使用间接关系:

class User
  has_many :employments
  has_many :companies, through: :employments
  has_many :positions
  has_many :teams, through: :positions
end

class Company
  has_many :employments
  has_many :users, through: :employments
  has_many :teams, through: :users
end

class Team
  has_many :positions
  has_many :users, through: :positions
  has_many :companies, through: :users
end

# join model between User and Company
class Employment
  belongs_to :user
  belongs_to :company
end

# join model between User and Team
class Position
  belongs_to :user
  belongs_to :team
end

虽然您可能会使用单一的 3 路连接模型,但这违反了单一职责原则,并且不能很好地映射域。

3 路连接引入了相当多的复杂性,因为您不能通过删除连接表中的一行来简单地取消两个记录的链接。并且 ActiveRecord 不会自动跟踪外键列。

如果您想向此数据模型添加角色,有以下几种方法:

1 在连接表中添加一个enum

# join model between User and Team
class Position
  enum role: [:grunt, :supervisor]
  belongs_to :user
  belongs_to :team
end

2 创建一个可重用的角色系统。

class User
  has_many :user_roles
  has_many :roles, through: :user_roles

  def has_role?(name, resource = nil)
    roles.exists?(name: name, resource: resource)
  end
end

class Role
  belongs_to :resource, polymorpic: true, optional: true
  has_many :user_roles
end

class UserRole
  belongs_to :user
  belongs_to :role
end

这是一个非常灵活的系统,可让您将角色附加到任何事物 - 公司、团队等。您还可以构建系统,其中角色甚至可以由最终用户定义。查看rolify gem 获取完整示例。

【讨论】:

  • 我的问题可能有点简单。我要再次更新它。它有 4 个连接,我想在连接中添加一个 supervisor:boolean 字段。又要更新问题了
  • 您应该只解释您想要实现的商业模式是什么,而不是如何实现。
  • 将其拆分为单独的连接表可能会更好。更新后你怎么看?
  • 我想我要重新考虑一下了。违反了单一责任规则。谢谢。
  • 我添加了一些关于如何将元数据和角色添加到此数据模型的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
  • 2016-01-07
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 2015-09-09
  • 2015-03-23
相关资源
最近更新 更多