Rails attr_accessor 父模型的属性在子模型中可用

Rails attr_accessor attribute on parent model available in children

上下文:

每个订单都有很多物品和物流。每个项目和物流(以及订单本身)都有很多收入。

我正在使用 accepts_nested_attributes_for on Order 同时创建 Order + Items & Logistics。但是,Revenues 是通过对每个模型 Order、Item 和 Logistics 使用 after_create 回调创建的。为什么?因为考虑到这些模型的解释差异,代码这样读起来更清晰。 (但如果这种做法是导致这个问题被问到的原因,我显然会重新考虑!)

我需要存储在 Revenues 中的一个关键属性是 pp_charge_id。但是 pp_charge_id 不是 Order、Items 或 Logistics 需要担心的事情。我已将 attr_accessor :pp_charge_id 附加到订单,因此可以正常工作,但是,一旦我进入子项目或物流模型,我就无法再访问 pp_charge_id,我需要再次保存相关收入。我应该怎么做?

控制器代码:

@order = Order.new(params) #params includes Order params, and nested params for child Item & Logistics
@order.pp_charge_id = "cash"
@order.save #I need this to not only save the Order, the children Item & Logistics, but then to also create the associated Revenue for each of the aforementioned 3 models

订购型号代码:

has_many :items
has_many :revenues

attr_accessor :pp_charge_id
after_create :create_revenue

def create_revenue
  self.revenues.create(pp_charge_id: self.pp_charge_id)
end

#This WORKS as expected because of the attr_accessor

ITEM/ LOGISTIC 型号代码:

has_many :revenues
belongs_to :order

after_create :create_revenue

def create_revenue
  self.revenues.create(pp_charge_id: self.order.pp_charge_id)
end

 #This DOES NOT work because self.order.pp_charge_id is nil

订购型号代码:

belongs_to :order
belongs_to :item
belongs_to :logistic

我再次了解 attr_accessor 并非设计用于在请求中持续存在,即使订单本身已重新加载。但是将它冗余地保存在一个没有用的 table 中也是没有意义的。如果执行此操作的唯一方法是将 pp_charge_id 放入订单的参数中并一次保存所有内容(包括收入),请告诉我,因为我知道该怎么做。 (同样,由于它的解释方式,我宁愿避免这种情况:参数来自用户,收入数据是我提供的)

而不是使用 after_create 和访问器,你应该考虑有一个正确的方法来做你需要的,即:

Order.create_with_charge(:cash, params)

我发现在数据库中保留冗余信息令人不安,只是因为这样代码读起来更清晰!

我认为如果您希望订单的 pp_charge_id 应用于其所有项目和物流,我会将所有这些都放入订单的 after_create 回调中:

# order.rb
def create_revenue
  revenues.create(pp_charge_id: pp_charge_id)
  items.each {|i| i.revenues.create(pp_charge_id: pp_charge_id)}
  logistics.each {|l| l.revenues.create(pp_charge_id: pp_charge_id)}
end

编辑:或者,您可以将 inverse_of 添加到您的 belongs_to 声明中,然后我相信 Item#create_revenue 会看到相同的 Order 你在控制器中设置的实例。所以如果你还添加了一个 attr_accessorItem class,你可以这样写它的 create_revenue

# item.rb
def create_revenue
  revenues.create(pp_charge_id: pp_charge_id || order.pp_charge_id)
end

这应该涵盖您在评论中提到的新要求。