在 Rails 4 中选择正确的模型关联
Choosing the right Model Associations in Rails 4
我无法决定哪种类型的关联最适合我的应用程序。我有以下型号:Firm
、Client
和 Case
。
一家公司处理许多个案。每个案例可以分配给 一个或多个 客户。因此我最初的做法是:
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.
除此之外:
# 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
、Client
和 Case
。
一家公司处理许多个案。每个案例可以分配给 一个或多个 客户。因此我最初的做法是:
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.
除此之外:
# 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