1

编辑:回想起来,这并不是一个好主意。您正在将属于的功能ZipWithCBSA放入其他人的模型中。收到关注的模型按预期行事,并且ZipWithCBSA响应的事实:store_locations在某种程度上应该是显而易见的ZipWithCBSA。它与其他模型/关注点无关。罗伯特·努贝尔用他的潜在解决方案使这一点显而易见。

是否可以在一个关注点中同时拥有 has_many 和 belongs_to 关系?

概述

我有一张表ZipWithCBSA,其中基本上包含一堆邮政编码元信息。

我有两个具有邮政编码的型号:StoreLocationPriceSheetLocation. 本质上:

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 的元编程还不是很流利。

4

1 回答 1

1

您最好的选择可能是在您的关注点包含在相关模型中时,使用class_exec模型类本身将关系添加到您的 ZipWithCBSA 模型中。例如,在included您关注的块内,添加:

relation_name = self.table_name
ZipWithCBSA.class_exec do
  has_many relation_name, foreign_key: :zip
end
于 2016-03-03T18:18:56.777 回答