首页 > 解决方案 > Rails 和 webpacker:在 Rails 操作中访问 Javascript 模块 (show.js.erb)

问题描述

我正在运行一个从 Rails 5.2 转换为 Rails 6 的应用程序,我正在尝试将 JS 从资产管道转换为 webpacker。

我通过 webpacker 使用 Rails UJS 来执行远程 AJAX 请求,这些请求应该接收和执行从服务器发回的 javascript 代码。

来自Rails 边缘文档

请注意 respond_to 块中的 format.js:它允许控制器响应您的 Ajax 请求。然后,您有一个相应的 app/views/users/create.js.erb 视图文件,该文件生成将在客户端发送和执行的实际 JavaScript 代码。

$("<%= escape_javascript(render @user) %>").appendTo("#users");

这就是我设置它的方式。

# app/views/users/index.html.erb
<%= link_to "New", new_user_path, remote: true %>
# app/controllers/users_controller.rb
def new
  @user = User.new
  # defaults response to new.js.erb
end
# app/views/users/new.js.erb
Dialog.showDialog("<%=j render('form') %>");

当 Rails UJS 执行users/new动作时,它应该执行返回的 JS 代码。Dialog但是,由于 webpacker 使用 es6 模块,我假设 Rails UJS 对JS 类一无所知。

我如何通知 Rails UJS 这个类,以便它可以执行 JS 代码响应?

这在 Rails 资产管道中具有完全的功能,我认为这是因为所有 JS 类都被添加到全局命名空间中(即,Dialog没有隐藏在任何模块后面)。

我正在尝试将其转换为 webpacker,并不断遇到Uncaught ReferenceError: Dialog is not defined错误。

# app/javascript/packs/application.js
import Dialog from "dialog"
# app/javascript/dialog.js
export default class Dialog {
  static showDialog(html) {
    ...JS to create and append element to body then show, etc...
  }
}
# config/webpack/environment.js
const { environment } = require("@rails/webpacker")
const webpack = require("webpack")

// Put into global namespace instead of importing in every file you use it.
environment.plugins.prepend("Provide",
  new webpack.ProvidePlugin({
    Rails: ["@rails/ujs"],
    $: "jquery",
    jQuery: "jquery"
  })
)

您如何再遵循 Rails 边缘指南中的示例代码?似乎在这种情况下使用 webpacker 和模块会破坏该示例。

我已经能够通过从服务器执行 vanilla JS 来解决我的部分用例,因此不需要Dialog定义我的类。

# app/views/users/new.js.erb 
document.body.appendChild(
  document.createRange().createContextualFragment("<%=j render 'form' %>")
)

但即便如此,我还是想创建某种实用程序类来抽象并将其缩短为:

Util.appendToBody("<%=j render 'form' %>")

这正好回到我开始的地方,试图访问一个Util无法访问的类,因为它的范围在 es6 模块中。

标签: javascriptruby-on-railswebpack

解决方案


推荐阅读