活动记录关联:has_and_belongs_to_many,has_many:通过或多态关联?

时间:2015-06-19 00:19:36

标签: ruby-on-rails activerecord database-design has-and-belongs-to-many polymorphic-associations

我正在处理的Ruby on Rails应用允许users与其他agendas一起创建和共享users

此外,我们必须能够:

  • 在其个人资料
  • 上显示每个agendas的{​​{1}}列表
  • 在议程页面上显示与user相关联的users列表
  • 与其他用户共享议程时,请为此用户定义agenda,并在上面提到的列表中显示该用户的角色

我打算在rolehas_and_belongs_to_many模型之间使用user关联,就像那样:

agenda

但后来我想知道这是否会让我在给定用户的给定议程页面上显示class User < ActiveRecord::Base has_and_belongs_to_many :agendas end class Agenda < ActiveRecord::Base has_and_belongs_to_many :users end @user.agenda.user.role列表。

我认为我应该选择roles关联,例如:

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

上述任何一种解决方案是否适合这种情况?

更新:做了一些研究,我偶然发现了这篇文章(从2012年开始),解释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 是一个比has_many :through更“聪明”的选择。就我而言,我仍然不确定has_and_belongs_to_many会有多少agenda

更新2 :正如@engineersmnkyn的评论中所建议的那样,解决这个问题的方法是使用两个连接表。我试图实现以下代码:

roles

我不确定语法。我是在正确的轨道上吗?我应该如何定义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模型?

更新3 :如果我选择了以下内容,该怎么办?

Role

然后,在迁移文件中,使用以下内容:

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.agenda.privilege来获取给定日程的特定用户的特权(创建者,编辑者或查看者的“角色”)?

相反,我可以打电话给@ agenda.user.privilege吗?

1 个答案:

答案 0 :(得分:1)

好的,我会先说我没有测试过这个,但我认为这两个选择中的一个应该适合你。

此外,如果这些连接表永远不需要除了关系之外的功能,那么has_and_belongs_to_many会更好,更简洁。

基本Rails经验法则:

  

如果您需要将关系模型作为自己的实体使用,请使用has_many:through。使用遗留模式或直接使用关系本身时,请使用has_and_belongs_to_many。

首先使用您的示例(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

这使用连接表来保存User&lt; =&gt;的关系。议程然后加入UserAgenda =&gt;表角色。

第二个选项是使用连接表来保存User&lt; =&gt;的关系。议程和另一个联接表来处理用户&lt; =&gt;的关系议程&lt; =&gt;角色。此选项将从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

我知道这是一个很长的答案,但我想在这种情况下向您展示解决问题的方法。希望它有所帮助