我可以在关注点中添加 has_many 和 belongs_to 关系的双方吗?
Can I add both sides of a has_many and belongs_to relationship in a concern?
编辑:回想起来,这并不是一个好主意。您正在将属于 ZipWithCBSA
的功能放入其他人的模型中。收到关注的模型按预期行事,ZipWithCBSA
响应 :store_locations
的事实在某种程度上应该是显而易见的 ZipWithCBSA
。与其他models/concern无关。支持 Robert Nubel 用他的潜在解决方案使这一点显而易见。
是否可以在一个问题中同时处理 has_many 和 belongs_to 关系?
概述
我有一个 table 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
页面上。为了防止每次查询时都为每个项目加入这个 table,我想将其中两个字段缓存到模型本身中——即
# 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 的元编程。
您最好的选择可能是在您的关注点包含在相关模型中时将关系添加到您的 ZipWithCBSA 模型中,在模型 class 本身上使用 class_exec
。例如,在您关注的 included
块内,添加:
relation_name = self.table_name
ZipWithCBSA.class_exec do
has_many relation_name, foreign_key: :zip
end
编辑:回想起来,这并不是一个好主意。您正在将属于 ZipWithCBSA
的功能放入其他人的模型中。收到关注的模型按预期行事,ZipWithCBSA
响应 :store_locations
的事实在某种程度上应该是显而易见的 ZipWithCBSA
。与其他models/concern无关。支持 Robert Nubel 用他的潜在解决方案使这一点显而易见。
是否可以在一个问题中同时处理 has_many 和 belongs_to 关系?
概述
我有一个 table 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
页面上。为了防止每次查询时都为每个项目加入这个 table,我想将其中两个字段缓存到模型本身中——即
# 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 的元编程。
您最好的选择可能是在您的关注点包含在相关模型中时将关系添加到您的 ZipWithCBSA 模型中,在模型 class 本身上使用 class_exec
。例如,在您关注的 included
块内,添加:
relation_name = self.table_name
ZipWithCBSA.class_exec do
has_many relation_name, foreign_key: :zip
end