包含 ActiveModel::Model 时,Sorbet 找不到 validates 方法

Sorbet can't find `validates` method when including `ActiveModel::Model`

我在 Rails 上使用 ActiveModel 来验证我 Ruby 中的一些表单对象。一个简化的可重现示例如下所示:

# typed: true

class Form
  include ActiveModel::Model
  
  # ...

  validates :name, presence: true
end

问题是,Sorbet 抱怨 validatesT.class_of(Form) 上不存在。即使为 ActiveModel::Model 模块正确生成了 RBI 文件。

您收到此错误的原因是,Sorbet 真的很难理解 ActiveSupport::Concern 的工作机制。

这里发生的事情是,当调用 include ActiveModel::Model 时,它会包含 ActiveModel::Validations。但是由于 ActiveModel::ModelActiveModel::Validations 都是问题,因此 ActiveModel::Model::ClassMethods ActiveModel::Validations::ClassMethods 都添加到 Form 使用 extend。是ActiveModel::Validations::ClassMethods提供了validates方法,而extend是Sorbet静态看不到的

首先,基本 srb 工具不了解 ActiveSupport::Concern 并且不会生成适当的 mixes_in_class_methods 调用来让 Sorbet 知道 ClassMethods也在玩。此外,即使生成了它,它也只会应用于包含的一个级别,并且在这种情况下会失败。

解决方法是在 Form 中显式添加一个 extend ActiveModel::Validations::ClassMethods,但这很难看。

最好的解决方案是切换到 Tapioca 工具以生成适当的 RBI 输出以解决问题。我们也将很快开始为像这样的嵌套关注点生成一个解决方案,这应该能很好地解决这个问题。