在 Rails 4 中选择正确的模型关联

Choosing the right Model Associations in Rails 4

我无法决定哪种类型的关联最适合我的应用程序。我有以下型号: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 协会会更好,但我不确定。

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

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

迁移加入table rails g migration CreateJoinTableCaseClient case client

Rails Guides says that “You should use has_many :through if you need validations, callbacks, or extra attributes on the join model”. As the great coding philosopher Avi Flombaum once eluded, how can you possibly know that your join model will not serve an additional purpose this early in the application process. No matter where you are in the development stage, you can never see so far in the future to know you will not need to extend the join table.

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