【问题标题】:What's the most idiomatic way to model this relationship in Rails?在 Rails 中建模这种关系的最惯用的方法是什么?
【发布时间】:2013-06-04 01:09:07
【问题描述】:

假设我们有教练、客户和用户。

以非继承的方式对此进行建模的理想方法是什么?我想避免 STI。

现在我有这样的东西:

用户.rb

  has_many :coaches, :foreign_key => :client_id
  has_many :coach_users, :through => :coaches, :source => :user
  has_many :clients, :class_name => "Coach"
  has_many :client_users, :through => :clients, :source => :client


  def is_a_coach_of?(client)
    self.client_users.include?(client)
  end

  def is_a_client_of?(coach)
    self.coach_users.include?(coach)
  end

coach.rb

  belongs_to :user
  belongs_to :client, :class_name => "User"

但是,要处理一个被认为是“教练”的用户对象并且必须键入 user.coach_users 来获取由该特定用户指导的用户集合,这感觉真的很笨重。

感觉非常不习惯,老实说,它只是令人困惑,我讨厌它。我想要更优雅的东西。

我想删除连接模型,只在 user.rb 模型上添加两个 has_many,但它仍然感觉很笨拙,尤其是违反对象角色的恶心感觉。这些是不同的角色,但也非常相似,因为它们都是用户。您如何使用 Rails 和 Ruby 以优雅的方式,以正确的惯用方式分离这些常见逻辑?

“网站用户”可以在不是coachclient 的情况下存在。

如果建模只需要一个关系,那么我可以看到它是一个 HABTM,但如果单个关系需要额外的逻辑怎么办?例如,客户或教练的额外逻辑?你会在 User 模型中混入一个定义逻辑的类吗?或者您会为这种关系创建单独的 AR 模型吗?如果是,如何创建?

【问题讨论】:

  • 为什么要避免使用 STI?这是一个很好的例子。
  • 据我所知,STI 通常不是解决问题的好方法,但如果这是完美的情况......
  • STI 如果操作得当,效果会很好,尽管它很容易被误用。请注意,User 将成为一个抽象类,您只能通过它的子类与它进行交互。例如,必须实例化 CoachClient,而不是 User。尽管如此,还是有很多人打破了这个规则,加入了肮脏的黑客来减少 Rails 的内置支持,感到沮丧并写博客文章指责 STI 是“糟糕的解决方案”。如果你愿意放弃对User的控制权,我会为你写一个答案。
  • 不过就是这样,也会有用户。用户可以存在而不是clientcoach。客户或教练只是用户之间的一种关系,可能有也可能没有这种关系。

标签: ruby-on-rails activerecord


【解决方案1】:

如果client/coach 只是一个关系,它可以只是那个关系,而不是一个单独的模型。所以你可以在Users 之间建立has_and_belongs_to_many 关系。使用以下命令创建迁移:

  def up
    create_table :coaches_clients do |t|
      t.integer :coach_id
      t.integer :client_id
    end
  end

在你的模型中:

has_and_belongs_to_many :clients,
        :foreign_key => 'client_id',
        :association_foreign_key => 'coach_id',
        :class_name => 'User',
        :join_table => 'coaches_clients'

has_and_belongs_to_many :coaches,
        :foreign_key => 'coach_id',
        :association_foreign_key => 'client_id',
        :class_name => 'User',
        :join_table => 'coaches_clients'

【讨论】:

  • 好的,谢谢。说得通。如果您要对客户或教练可能需要额外逻辑这一事实采取预防措施,您将如何在这个意义上对其进行建模?
  • 这真的取决于您的需求,但我发现拥有user 模型、has_one 教练模型和has_one 客户端模型很方便。这样,您可以分别在用户中拥有与用户相关的用户详细信息和逻辑,并且用户可以是教练、客户,或者两者都不是。这样,教练逻辑可以进入coach 模型。不知道它是多么地道,我猜你会打电话给user.coach.clients 之类的。
猜你喜欢
  • 2010-12-28
  • 1970-01-01
  • 2010-12-14
  • 1970-01-01
  • 2019-04-29
  • 2016-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多