Active Record Associations: has_and_belongs_to_many, has_many :through or polymorphic association?
Active Record Associations: has_and_belongs_to_many, has_many :through or polymorphic association?
我正在开发的 Rails 应用程序上的 Ruby 允许 users
创建并与其他 users
共享 agendas
。
此外,我们必须能够:
- 在他的个人资料
中为每个 user
显示 agendas
的列表
- 在议程页面上显示与
agenda
关联的 users
的列表
- 与其他用户共享议程时,为该用户定义一个
role
,并在上面提到的列表中显示该用户的角色
我打算在 user
和 agenda
模型之间建立 has_and_belongs_to_many
关联,例如:
class User < ActiveRecord::Base
has_and_belongs_to_many :agendas
end
class Agenda < ActiveRecord::Base
has_and_belongs_to_many :users
end
但后来我想知道这是否能让我在给定用户的给定议程页面上获取并显示 roles
的 @user.agenda.user.role
列表。
而且我认为我应该改用 has_many :through
关联,例如:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
虽然我对 user
有几个 roles
(每个 agenda
一个)的想法很满意,但我不确定 agenda
有几个roles
(每个user
?)。
最后,更让人困惑的是,我阅读了有关多态关联的内容,认为它也可能是一个可行的解决方案,例如,如果这样做的话:
class Role < ActiveRecord::Base
belongs_to :definition, polymorphic: true
end
class User < ActiveRecord::Base
has_many :roles, as: :definition
end
class Agenda < ActiveRecord::Base
has_many :roles, as: :definition
end
以上任何解决方案听起来是否适合这种情况?
更新:在做一些研究时,我偶然发现这篇文章(从 2012 年开始)解释说 has_many :through
比 has_and_belongs_to_many
更 "smarter" ].就我而言,我仍然不确定 agenda
会有很多 roles
.
更新 2:正如@engineersmnkyn 在评论中所建议的那样,解决此问题的一种方法是使用两个连接表。我尝试实现以下代码:
class User < ActiveRecord::Base
has_many :agendas, through: :jointable
end
class Agenda < ActiveRecord::Base
end
class Role < ActiveRecord::Base
end
class Jointable < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :agendaroles through :jointable2
end
class Jointable2 < ActiveRecord::Base
belongs_to :roles
belongs_to :useragenda
end
虽然我不确定语法。我在正确的轨道上吗?我应该如何定义 Agenda
和 Role
模型?
更新 3:如果我使用类似的东西会怎样:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
然后,在迁移文件中,使用如下内容:
class CreateRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.belongs_to :user, index: true
t.belongs_to :agenda, index: true
t.string :privilege
t.timestamps
end
end
end
我能否调用@user.agenda.privilege 来获得给定用户针对给定议程的特权("role" 创建者、编辑者或查看者)?
相反,我可以调用@agenda.user.privilege吗?
好吧,我先说我没有测试过这个,但我认为这两个选择之一应该适合你。
此外,如果这些联接 table 永远不需要关系以外的功能,那么 has_and_belongs_to_many
会很好并且更简洁。
基本Rails经验法则:
If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.
首先使用您的示例 (http://repl.it/tNS):
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda:agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user_agenda
end
这使用连接 table 来保存 User <=> Agenda 的关系,然后使用 table 来连接 UserAgenda => Role。
第二个选项是使用连接 table 来保存 User <=> Agenda 的关系,另一个连接 table 来处理 User <=> Agenda <=> Role 的关系.从 CRUD 的角度来看,此选项需要进行更多设置,例如验证用户是否是该议程的用户,但允许一点灵活性。
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda: agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user
belongs_to :agenda
end
我知道这是一个很长的答案,但我想向您展示不止一种方法来解决这个问题。希望对你有帮助
我正在开发的 Rails 应用程序上的 Ruby 允许 users
创建并与其他 users
共享 agendas
。
此外,我们必须能够:
- 在他的个人资料 中为每个
- 在议程页面上显示与
agenda
关联的users
的列表 - 与其他用户共享议程时,为该用户定义一个
role
,并在上面提到的列表中显示该用户的角色
user
显示 agendas
的列表
我打算在 user
和 agenda
模型之间建立 has_and_belongs_to_many
关联,例如:
class User < ActiveRecord::Base
has_and_belongs_to_many :agendas
end
class Agenda < ActiveRecord::Base
has_and_belongs_to_many :users
end
但后来我想知道这是否能让我在给定用户的给定议程页面上获取并显示 roles
的 @user.agenda.user.role
列表。
而且我认为我应该改用 has_many :through
关联,例如:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
虽然我对 user
有几个 roles
(每个 agenda
一个)的想法很满意,但我不确定 agenda
有几个roles
(每个user
?)。
最后,更让人困惑的是,我阅读了有关多态关联的内容,认为它也可能是一个可行的解决方案,例如,如果这样做的话:
class Role < ActiveRecord::Base
belongs_to :definition, polymorphic: true
end
class User < ActiveRecord::Base
has_many :roles, as: :definition
end
class Agenda < ActiveRecord::Base
has_many :roles, as: :definition
end
以上任何解决方案听起来是否适合这种情况?
更新:在做一些研究时,我偶然发现这篇文章(从 2012 年开始)解释说 has_many :through
比 has_and_belongs_to_many
更 "smarter" ].就我而言,我仍然不确定 agenda
会有很多 roles
.
更新 2:正如@engineersmnkyn 在评论中所建议的那样,解决此问题的一种方法是使用两个连接表。我尝试实现以下代码:
class User < ActiveRecord::Base
has_many :agendas, through: :jointable
end
class Agenda < ActiveRecord::Base
end
class Role < ActiveRecord::Base
end
class Jointable < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :agendaroles through :jointable2
end
class Jointable2 < ActiveRecord::Base
belongs_to :roles
belongs_to :useragenda
end
虽然我不确定语法。我在正确的轨道上吗?我应该如何定义 Agenda
和 Role
模型?
更新 3:如果我使用类似的东西会怎样:
class User < ActiveRecord::Base
has_many :roles
has_many :agendas, through: :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class Agenda < ActiveRecord::Base
has_many :roles
has_many :users, through: :roles
end
然后,在迁移文件中,使用如下内容:
class CreateRoles < ActiveRecord::Migration
def change
create_table :roles do |t|
t.belongs_to :user, index: true
t.belongs_to :agenda, index: true
t.string :privilege
t.timestamps
end
end
end
我能否调用@user.agenda.privilege 来获得给定用户针对给定议程的特权("role" 创建者、编辑者或查看者)?
相反,我可以调用@agenda.user.privilege吗?
好吧,我先说我没有测试过这个,但我认为这两个选择之一应该适合你。
此外,如果这些联接 table 永远不需要关系以外的功能,那么 has_and_belongs_to_many
会很好并且更简洁。
基本Rails经验法则:
If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.
首先使用您的示例 (http://repl.it/tNS):
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda:agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles, through: :user_agendas
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user_agenda
end
这使用连接 table 来保存 User <=> Agenda 的关系,然后使用 table 来连接 UserAgenda => Role。
第二个选项是使用连接 table 来保存 User <=> Agenda 的关系,另一个连接 table 来处理 User <=> Agenda <=> Role 的关系.从 CRUD 的角度来看,此选项需要进行更多设置,例如验证用户是否是该议程的用户,但允许一点灵活性。
class User < ActiveRecord::Base
has_many :user_agendas
has_many :agendas, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def agenda_roles(agenda)
roles.where(user_agenda_roles:{agenda: agenda})
end
end
class Agenda < ActiveRecord::Base
has_many :user_agendas
has_many :users, through: :user_agendas
has_many :user_agenda_roles
has_many :roles, through: :user_agenda_roles
def user_roles(user)
roles.where(user_agenda_roles:{user: user})
end
end
class Role < ActiveRecord::Base
has_many :user_agenda_roles
end
class UserAgenda < ActiveRecord::Base
belongs_to :user
belongs_to :agenda
end
class UserAgendaRoles < ActiveRecord::Base
belongs_to :role
belongs_to :user
belongs_to :agenda
end
我知道这是一个很长的答案,但我想向您展示不止一种方法来解决这个问题。希望对你有帮助