rails 4 "chained" has_one: :through relations work with persisted but not new objects

rails 4 "chained" has_one: :through relations work with persisted but not new objects

我有一个相当复杂的模型设置:

class LineItem < ActiveRecord::Base # STI parent class
end

class VendorLineItem < LineItem
  belongs_to: :unit_rate, class_name: 'Billing::UnitRate'
  has_one :contract_resource, through: :unit_rate
  has_one :resource, through: :contract_resource
end

请注意,以上两个 class 没有命名空间,而下面的关联模型都位于 Billing 命名空间中。

class Billing::UnitRate < ActiveRecord::Base
  belongs_to :contract_resource, class_name: 'Billing::ContractResource'
  has_one :contract, through: :contract_resource
  has_one :resource, through: :contract_resource
  has_many :vendor_line_items, dependent: :destroy
end

class Billing::ContractResource < ActiveRecord::Base  
  belongs_to :contract
  belongs_to :resource, class_name: 'Billing::Resource'  
  has_many :unit_rates, dependent: :destroy
end

class Billing::Resource < ActiveRecord::Base
  has_many :contract_resources
  has_many :contracts, through: :contract_resources
  has_many :unit_rates, through: :contract_resources
end

我的问题是 VendorLineItem class,我需要在其中获取关联的 resource

如果我正在处理持久数据,一切都很好。在 rails 控制台中:

2.2.3 :001 > x = VendorLineItem.last
  VendorLineItem Load (9.8ms)  SELECT  "line_items".* FROM "line_items" WHERE "line_items"."type" IN ('VendorLineItem')  ORDER BY "line_items"."id" DESC LIMIT 1
 => #<VendorLineItem id: 42, fire_id: 938774, type: "VendorLineItem", unit_rate_id: 716, units_utilized: #<BigDecimal:6184d30,'0.1E1',9(18)>, fire_department_id: nil, dollar_amount: nil, created_at: "2016-11-18 16:22:23", updated_at: "2016-11-18 16:22:23", total: #<BigDecimal:6184060,'0.25E2',9(18)>> 
2.2.3 :002 > x.resource
  Billing::Resource Load (8.9ms)  SELECT  "billing"."resources".* FROM "billing"."resources" INNER JOIN "contracts_resources" ON "billing"."resources"."id" = "contracts_resources"."resource_id" INNER JOIN "billing"."unit_rates" ON "contracts_resources"."id" = "billing"."unit_rates"."contract_resource_id" WHERE "billing"."unit_rates"."id" =  LIMIT 1  [["id", 716]]
 => #<Billing::Resource id: 39, name: nil, description: nil, code: nil, sort_order: nil, is_active: true, constant_name: "E0", created_at: "2015-10-14 15:59:00", updated_at: "2015-10-14 15:59:00", vendor_id: 1, resource_type_id: 37> 

如果,OTOH,我正在使用一个新实例,resource 返回为 nil(rails 甚至不尝试;没有发出 sql)。

2.2.3 :003 > vli = VendorLineItem.new unit_rate_id: 711
 => #<VendorLineItem id: nil, fire_id: nil, type: "VendorLineItem", unit_rate_id: 711, units_utilized: nil, fire_department_id: nil, dollar_amount: nil, created_at: nil, updated_at: nil, total: nil> 
2.2.3 :004 > vli.resource
 => nil 

但我可以通过关联的显式链访问资源:

2.2.3 :005 > vli.unit_rate.contract_resource.resource
  Billing::UnitRate Load (8.9ms)  SELECT  "billing"."unit_rates".* FROM "billing"."unit_rates" WHERE "billing"."unit_rates"."id" =  LIMIT 1  [["id", 711]]
  Billing::ContractResource Load (8.8ms)  SELECT  "contracts_resources".* FROM "contracts_resources" WHERE "contracts_resources"."id" =  LIMIT 1  [["id", 261]]
  Billing::Resource Load (8.7ms)  SELECT  "billing"."resources".* FROM "billing"."resources" WHERE "billing"."resources"."id" =  LIMIT 1  [["id", 34]]
=> #<Billing::Resource id: 34, name: nil, description: nil, code: nil, sort_order: nil, is_active: true, constant_name: "D5", created_at: "2015-10-14 15:59:00", updated_at: "2015-10-14 15:59:00", vendor_id: 1, resource_type_id: 19> 

我也可以通过has_one :contract_resource, through: :unit_rate关联找到资源没有问题:

2.2.3 :007 >   vli.contract_resource.resource
  Billing::ContractResource Load (8.7ms)  SELECT  "contracts_resources".* FROM "contracts_resources" INNER JOIN "billing"."unit_rates" ON "contracts_resources"."id" = "billing"."unit_rates"."contract_resource_id" WHERE "billing"."unit_rates"."id" =  LIMIT 1  [["id", 711]]
  Billing::Resource Load (8.7ms)  SELECT  "billing"."resources".* FROM "billing"."resources" WHERE "billing"."resources"."id" =  LIMIT 1  [["id", 34]]
=> #<Billing::Resource id: 34, name: nil, description: nil, code: nil, sort_order: nil, is_active: true, constant_name: "D5", created_at: "2015-10-14 15:59:00", updated_at: "2015-10-14 15:59:00", vendor_id: 1, resource_type_id: 19> 

为什么 has_one: resource, through: :contract_resource 协会在这里不起作用?

事实证明这是 rails 中长期存在的错误:

https://github.com/rails/rails/issues/20827 [关闭]

https://github.com/rails/rails/issues/33155 [此处重新打开]