0

在 Rails 7 中,Turbolinks 被 Hotwire / Turbo 取代。这会修补 Web 链接,使它们成为 AJAX 样式的请求,就像 Turbolinks 所做的那样,而且还修补了表单。总的来说,我们发现这破坏了我们的应用程序。

  • 已经附加了某种 JS 行为的表单会发生冲突。
  • 标准 Rails 错误处理习惯用法 - “设置flashrender :new/ render :edit” - 令人惊讶地打破;必须添加status: :unprocessable_entity和交叉手指。
  • 如果处理表单提交的控制器重定向到一个包含补丁锚 ( ...#foo) 的 URL,Turbo 会删除它。

最后,data: {turbo: false}将代码分散到整个代码库中才有意义。更糟糕的是,我们使用的是 SimpleForm,所以这变得更加麻烦html: {data: {turbo: false}}

有没有办法 _globally为表单禁用 Turbo (理想情况下,所有表单,无论其来源如何 - 请让<form>标签和其中的所有内容完全独立)但保持其其余行为不变?

4

1 回答 1

0

我在 Stack Overflow 上发布了这个问答,因为我找不到任何其他解决方案。显然,有许多缺点,我更希望看到一个简单的 Turbo 配置标志,它会使其忽略表单——这将是一种非常可取的方法。

无论哪种方式,我仍然没有完整的解决方案,因为 Rails 内部为例如 a 生成的表单link_to(...method: delete)仍然是一个问题,但我确实使用一些猴子补丁解决了其中一些问题。

一方面有 Rails 形式:

  • 显然,data-turbo属性的值适用于该节点和所有子节点,因此可以包装例如 Rails 生成的“动态”表单,例如来自link_to(...method: delete)具有该属性集的 DIV 中的 a,并且至少可以解决这些问题。以案例为基础 -尽管请注意,在某些情况下我仍然无法完成这项工作
  • 但是,如果您有很多这些,那将是侵入性和丑陋的,因此有一种方法让 Turbo 完全忽略表单仍然很好。

另一方面,有 SimpleForm 形式:

  • SimpleForm 无法全局配置将添加到form其构造的元素的数据属性。迄今为止,GitHub 问题中对此的先前请求已被明确拒绝。
  • SimpleForm 似乎没有提供任何方法来配置将围绕整个表单的包装器,仅提供用于表单内输入的自定义包装器。所以我们不能像上面提到的那样简单地编写一个包装器 DIV。

我碰巧参与了一个叫做 Hoodoo 的 gem,它提供了猴子补丁工具,可以让你编写更像子类的补丁模块 -super可以调用补丁实现 - 而且,补丁可以动态轻松地启用或禁用. Hoodoo 实际上是一个 Rack 应用程序服务框架,所以这有点像大锤——我一直打算有朝一日将它提取到它自己的 gem 中,但在撰写本文时,我还没有考虑到它(几年过去了) by) - 但我们可以require只选择我们需要的部分而忽略其余部分。

在这里,我修补了 SimpleForm 的构建器方法。这些只是在引擎盖下调用 Rails 的表单助手,所以我可能会尝试在 Rails 中向下修补,但无论如何,以下工作有效。

在您的Gemfile中,声明 Hoodoo 依赖项,但不要加载其所有组件,因为您不需要它们中的大部分。

# Hoodoo's monkey patch module is useful sometimes:
# https://rubygems.org/gems/hoodoo
#
# MUST use 'require: false' so that the Rack components of Hoodoo middleware
# do not get activated; this is a Rails app, not a Hoodoo service!
#
gem 'hoodoo', '~> 2.12', require: false

...然后写一些config/initializers/simple_form_monkey_patch.rb看起来像这样的东西:

require 'hoodoo/monkey'

module SimpleFormMonkey
  module InstanceExtensions
    def simple_form_for(record, options = {}, &block)
      modified_options = {html: {data: {turbo: false}}}
      modified_options.deep_merge!(options)

      super(record, modified_options, &block)
    end
  end
end

Hoodoo::Monkey.register(
  extension_module: SimpleFormMonkey,
  target_unit:      SimpleForm::ActionViewExtensions::FormHelper
)

Hoodoo::Monkey.enable(
  extension_module: SimpleFormMonkey
)

……这样就行了。这有一些风险,因为我们正在修补一些东西——就模块名称和嵌套而言——在技术上对 SimpleForm 来说是私有的,但方法签名本身至少是公开的。如果您想降低级别并修补长期稳定的 API,则可以ActionView::Helpers::FormHelper使用覆盖进行修补。form_for由于方法签名相同,因此代码几乎相同。

于 2022-01-31T04:33:09.273 回答