如何在Rails7的Dry::Struct中通过方法设置settlements属性?
问题原因
你遇到的报错是因为fetch_settlements是实例方法,而在类定义阶段(编写attribute :settlements...代码时),还没有创建任何Payout实例,类上下文里根本找不到这个方法,自然会报未定义的错误。
正确实现方式
这个需求是可以实现的,有两种常用方案:
方案一:使用dry-types的延迟执行默认值
dry-types支持传入一个块作为默认值,这个块会在实例化对象时执行,此时已经生成了实例,可以正常调用fetch_settlements方法:
module Customer class Payout < Dry::Struct attribute :amount, Types::Integer attribute :reference, Types::String # 用块延迟执行默认值,块内的self为当前Payout实例 attribute :settlements, Types::Array.optional.default { fetch_settlements } def fetch_settlements CustomerApi.fetch_settlements_by_reference(platform_merchant_id, reference) end end end
注意:这种方式下,只有初始化Payout时未传入settlements参数,才会执行块内的fetch_settlements来赋值。
方案二:重写initialize方法或使用after_initialize钩子
如果需要无论是否传入settlements都要覆盖/补充数据,或者逻辑更复杂,可以用以下两种方式:
方式A:重写initialize方法
module Customer class Payout < Dry::Struct attribute :amount, Types::Integer attribute :reference, Types::String attribute :settlements, Types::Array.optional def initialize(attributes) super # 若settlements为空,调用方法获取并赋值 self.settlements ||= fetch_settlements end def fetch_settlements CustomerApi.fetch_settlements_by_reference(platform_merchant_id, reference) end end end
方式B:使用after_initialize钩子
dry-struct支持after_initialize回调,会在实例初始化完成后执行:
module Customer class Payout < Dry::Struct attribute :amount, Types::Integer attribute :reference, Types::String attribute :settlements, Types::Array.optional after_initialize do self.settlements ||= fetch_settlements end def fetch_settlements CustomerApi.fetch_settlements_by_reference(platform_merchant_id, reference) end end end
这种方式代码逻辑更清晰,适合处理初始化后的补充逻辑。
内容的提问来源于stack exchange,提问作者mr_muscle
相关产品推荐
相关产品推荐

