【问题标题】:Choosing the right Model Associations in Rails 4在 Rails 4 中选择正确的模型关联
【发布时间】:2015-08-07 08:41:55
【问题描述】:

我无法确定哪种关联类型最适合我的应用程序。我有以下型号:FirmClientCase

一个公司处理许多案例。每个案例都可以有一个或多个 客户分配给它。因此我最初的做法是:

class Firm < ActiveRecord::Base
   has_many :cases
   has_many :clients
end

class Case < ActiveRecord::Base
   belongs_to :firm
   has_many :clients
end

class Client < ActiveRecord::Base
   belongs_to :firm
   has_many :cases
end

但我认为这有点不对劲。我在想has_many :through 协会会更好,但我不确定。

【问题讨论】:

  • 因为一个案例可以有很多客户,一个客户可以有很多案例,所以需要一个has_many_through关联。公司可以有不属于客户的案例吗?
  • 没有。案例必须始终涉及客户。
  • @Jaime 在客户端模型中,您必须存储 case_id 和firm_id..我说的对吗?
  • @margo 如果公司可以有没有案例的客户,has_many :through 是不够的,是吗? @Jaime:没有案例的客户可以存在吗?
  • 应该是。客户案例关系不一定是强制性的。只需确保您定义了您的直通表并创建迁移。

标签: ruby-on-rails ruby-on-rails-4 model rails-activerecord model-associations


【解决方案1】:

Rails Guides 说“如果您需要验证、回调或连接模型上的额外属性,您应该使用 has_many :through”。正如伟大的编码哲学家 Avi Flombaum 曾经逃避的那样,你怎么可能知道你的连接模型在申请过程的早期不会起到额外的作用。无论您处于开发阶段的哪个阶段,您永远无法看到未来这么远知道您不需要扩展连接表。

Why You Don’t Need Has_and_belongs_to_many Relationships

顺便说一句:

# models/firm.rb
class Firm < ActiveRecord::Base
    has_many :clients
    has_many :cases, through: :clients
end

# models/client.rb
class Client < ActiveRecord::Base
    belongs_to :firm
    has_many :client_cases
    has_many :cases, through: :client_cases
end

# models/case.rb
class Case < ActiveRecord::Base
    has_many :client_cases
    has_many :clients, through: :client_cases
end

# models/client_case.rb
class ClientCase < ActiveRecord::Base
    belongs_to :client
    belongs_to :case
end

更新

您的问题必须在其他地方;我能够在终端中创建以下内容而没有任何错误。

f = Firm.create name: 'Magical Group' # => #<Firm id: 1...
b = f.clients.create name: 'Billy' # => #<Client id: 1...
m = f.clients.create name: 'Megan' # => #<Client id: 2...
c = Case.create name: 'Billy & Megan are getting married!' # => #<Case id: 1...
b.cases << c # => #<ActiveRecord::Associations::CollectionProxy
m.cases << c # => #<ActiveRecord::Associations::CollectionProxy
f.cases.count # => 2
f.cases.uniq.count # => 1

我已经提供了数据库架构,请确保您的类似于:

ActiveRecord::Schema.define(version: 20150813173900) do

    create_table "cases", force: :cascade do |t|
        t.string   "name"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
    end

    create_table "client_cases", force: :cascade do |t|
        t.integer  "client_id"
        t.integer  "case_id"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
    end

    add_index "client_cases", ["case_id"], name: "index_client_cases_on_case_id"
    add_index "client_cases", ["client_id"], name: "index_client_cases_on_client_id"

    create_table "clients", force: :cascade do |t|
        t.string   "name"
        t.integer  "firm_id"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
    end

    add_index "clients", ["firm_id"], name: "index_clients_on_firm_id"

    create_table "firms", force: :cascade do |t|
        t.string   "name"
        t.datetime "created_at", null: false
        t.datetime "updated_at", null: false
    end

end

【讨论】:

  • 这看起来不错,但如果可能存在没有客户关联的情况下可以存在案例的情况,那么我也会在公司和案例之间添加直接关联。无论如何我都会很想这样做,因为我觉得应该有一种方法可以做(例如) Firm.first.cases 而无需在结果上调用 uniq。
  • 感谢您的回答,但是我有点困惑,为什么需要 Case 和 ClientCase 模型?
  • 这实质上是写出has_and_belongs_to_many 关联。 ClientCase 模型充当您的连接表,就像 HABTM 一样,并允许您更好地控制如何使用连接模型。我建议你仔细阅读the article我在我的答案中发布的内容。
  • 谢谢。但是有一个问题:如果我想访问一家公司的所有卡索怎么办?也许执行计数,执行每个等。我如何能够在视图中实现这一点?
  • 因为Firm has_many :cases, through: :clients 你可以直接调用@firm.cases.uniq.count
【解决方案2】:

假设一个案件永远不会属于不同的公司:

class Firm < ActiveRecord::Base
    has_many :clients
    has_many :cases, through: :clients
end

class Client < ActiveRecord::Base
    belongs_to :firm
    has_and_belongs_to_many :cases
end

class Case < ActiveRecord::Base
    has_and_belongs_to_many :clients
end

迁移连接表 rails g migration CreateJoinTableCaseClient case client

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-26
    • 1970-01-01
    • 1970-01-01
    • 2013-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多