You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 19:41:54