我有3个模型用户项目Bug。我想通过创建多对多的关系。我在模型中创建关系,我不知道它是否正确,用户有用户类型列,这是enum类型用户类型包含developer, manager, QA
user.user_type.manager belong to many project it has one to many relation
user.user_type.developer has many project and many project belong to developer. it has many to many realtion
project has many bugs and bugs belong to project
developer has many bugs and many bugs belong to developer
错误模型
class Bug < ApplicationRecord
belongs_to :project
has_many :developers, -> { where user_type: :Developer }, class_name: 'User', through: :project, source: :bugs
end
项目模型class Project < ApplicationRecord
has_many :bugs, dependent: :delete_all
has_many :developers, -> { where user_type: :Developer }, class_name: 'User', through: :users, source: :project
has_many :users //it belong to manager_id
end
用户模型class User < ApplicationRecord
enum user_type: %i[Manager Developer QA]
has_many :projects
has_many :bugs
end
developer_bug模型class DevelopersBug < ApplicationRecord
has_many :bugs
has_many :users
end
project_developer模型class ProjectsDeveloper < ApplicationRecord
has_many :projects
has_many :users
end
This
has_many :developers, -> { where user_type: :Developer },
class_name: 'User',
through: :users,
source: :project
不是你想的那样。它的意思是:
我已经有一个关联'users'。用户有一个关联项目
请配置一个关联,使两个join并给我与关联用户关联的项目列表。
这个关联将被命名为"developer "并且属于"用户"类的对象。
你可以看到这些指令是如何不一致的。这个
has_many :projects, through: :users, source: :project
将通过跳过用户定义一个相关项目列表。
另一边是:
has_many :developers, -> { where user_type: :Developer }, class_name: 'User'
将定义一个与所有用户子集直接的多用户关联。
根据你的描述,你的数据模型似乎是错误的,也许这样会更好:
class User < ApplicationRecord
has_many :managed_projects, inverse_of: :manager, class_name: 'Project'
has_and_belongs_to_many :projects
has_many :bugs
end
class Project < ApplicationRecord
belongs_to :manager, class_name: 'User', inverse_of: :managed_projects
has_and_belongs_to_many :users
has_many :bugs
end
class Bug < ApplicationRecord
belongs_to :user
belongs_to :project
end
您的模式应该包括这三个表,以及一个额外的多对多连接表projects_users
,它保存用户和项目的外键。
正如rewritten在他出色的回答中已经指出的那样,您的数据模型存在缺陷。您需要的是连接用户和项目的连接表:
class User < ApplicationRecord
has_many :project_roles
has_many :projects, through: :project_roles
end
class ProjectRole < ApplicationRecord
belongs_to :user
belongs_to :project
end
class Project < ApplicationRecord
has_many :users
has_many :projects, through: :project_roles
end
如果你想在项目中给用户特定的角色,你可以将enum添加到join表中,这就是它开始变得复杂的地方,所以请耐心听我说:
class ProjectRole < ApplicationRecord
enum roles: [:manager, :developer, :qa]
belongs_to :user
belongs_to :project
end
class User < ApplicationRecord
has_many :project_roles
has_many :projects, through: :project_roles
has_many :project_roles_as_manager,
-> { manager }, # short for `where(role: :manager)`
class_name: 'ProjectRole'
has_many :projects_as_manager,
class_name: 'Project',
through: :project_roles_as_manager,
source: :project
has_many :project_roles_as_developer,
-> { developer },
class_name: 'ProjectRole'
has_many :projects_as_developer,
class_name: 'Project',
through: :project_roles_as_developer,
source: :project
# ...
end
定义具有默认作用域的关联,然后通过该关联进行连接。然后在关联的另一端执行同样的操作:
class Project < ApplicationRecord
has_many :users
has_many :projects, through: :project_roles
has_many :manager_project_roles,
-> { manager },
class_name: 'ProjectRole'
has_many :managers,
through: :manager_project_roles,
source: :user
# ...
end
当然,这是大量的重复,你可以通过循环ProjectRoles.roles.keys
和动态定义关联来减少。
这是一种非常灵活的建模方式,它对域的假设尽可能少。例如,它允许一个项目有多个经理,它允许用户在不同的项目中有不同的角色。
如果你想建模"bug "正如您通常在跟踪器中处理问题一样,您将为错误创建一个表,并为分配创建一个连接表:
class Bug < ApplicationRecord
belongs_to :project
has_many :bug_assignments
has_many :users, through: :bug_assignments
end
class BugAssignment < ApplicationRecord
has_one :project, through: :bug
belongs_to :bug
belongs_to :user
end
class User < ApplicationRecord
# ...
has_many :bug_assignments
has_many :bugs
end