编辑:回想起来,这并不是一个好主意。您正在将属于的功能ZipWithCBSA
放入其他人的模型中。收到关注的模型按预期行事,并且ZipWithCBSA
响应的事实:store_locations
在某种程度上应该是显而易见的ZipWithCBSA
。它与其他模型/关注点无关。罗伯特·努贝尔用他的潜在解决方案使这一点显而易见。
是否可以在一个关注点中同时拥有 has_many 和 belongs_to 关系?
概述
我有一张表ZipWithCBSA
,其中基本上包含一堆邮政编码元信息。
我有两个具有邮政编码的型号:StoreLocation
和PriceSheetLocation
. 本质上:
class ZipWithCBSA < ActiveRecord::Base
self.primary_key = :zip
has_many :store_locations, foreign_key: :zip
has_many :price_sheet_locations, foreign_key: :zip
end
class StoreLocation< ActiveRecord::Base
belongs_to :zip_with_CBSA, foreign_key: :zip
...
end
class PriceSheetLocation < ActiveRecord::Base
belongs_to :zip_with_CBSA, foreign_key: :zip
...
end
有两个属性ZipWithCBSA
我总是希望与我的其他模型一起返回,包括在#index
页面上。为了防止每次查询时为每个项目加入该表,我想将其中两个字段缓存到模型本身中——即
# quick schema overview~~~
ZipWithCBSA
- zip
- cbsa_name
- cbsa_state
- some_other_stuff
- that_I_usually_dont_want
- but_still_need_access_to_occasionally
PriceSheetLocation
- store
- zip
- cbsa_name
- cbsa_state
StoreLocation
- zip
- generic_typical
- location_address_stuff
- cbsa_name
- cbsa_state
所以,我添加了
after_save :store_cbsa_data_locally, if: ->(obj){ obj.zip_changed? }
private
def store_cbsa_data_locally
if zip_with_cbsa.present?
update_column(:cbsa_name, zip_with_cbsa.cbsa_name)
update_column(:cbsa_state, zip_with_cbsa.cbsa_state)
else
update_column(:cbsa_name, nil)
update_column(:cbsa_state, nil)
end
end
我希望将这些转移到关注点,所以我已经完成了:
# models/concerns/UsesCBSA.rb
module UsesCBSA
extend ActiveSupport::Concern
included do
belongs_to :zip_with_cbsa, foreign_key: 'zip'
after_save :store_cbsa_data_locally, if: ->(obj){ obj.zip_changed? }
def store_cbsa_data_locally
if zip_with_cbsa.present?
update_column(:cbsa_name, zip_with_cbsa.cbsa_name)
update_column(:cbsa_state, zip_with_cbsa.cbsa_state)
else
update_column(:cbsa_name, nil)
update_column(:cbsa_state, nil)
end
end
private :store_cbsa_data_locally
end
end
# ~~models~~
class StoreLocation < ActiveRecord::Base
include UsesCBSA
end
class PriceSheetLocation < ActiveRecord::Base
include UsesCBSA
end
这一切都很好——但我仍然需要手动将 has_many 关系添加到 ZipWithCBSA 模型中:
class ZipWithCBSA < ActiveRecord::Base
has_many :store_locations, foreign_key: zip
has_many :price_sheet_locations, foreign_key: zip
end
最后!问题!
是否可以重新打开ZipWithCBSA
并添加关注点的has_many
关系?或者以任何其他更自动的方式允许我指定一次这些特定系列的模型是 bffs?
我试过了
# models/concerns/uses_cbsa.rb
...
def ZipWithCBSA
has_many self.name.underscore.to_sym, foregin_key: :zip
end
...
并且
# models/concerns/uses_cbsa.rb
...
ZipWithCBSA.has_many self.name.underscore.to_sym, foregin_key: :zip
...
但都没有奏效。我猜这与在模型自己的初始化期间没有添加这些关系的事实有关......但是是否可以在单独的文件中定义模型的关系?
我对 Ruby 的元编程还不是很流利。