如何使 Rails.ajax(...) 在所有页面上工作?

Posted

技术标签:

【中文标题】如何使 Rails.ajax(...) 在所有页面上工作?【英文标题】:How to make Rails.ajax(...) work on all page? 【发布时间】:2021-07-31 19:57:49 【问题描述】:

您好,我正在尝试使用 Rails 6.1.3.1 上的 sweet alert 2 库执行 HTTP DELETE 请求!当我尝试这样的事情时,它完美地工作see my other question about this issue:

<button script='
Swal.fire(
  "Good job!",
  "You clicked the button!",
  "success"
)
location.pathname = "<%= home_about_path %>"; //redirect to About Page
'>TEST</button>

但这仅适用于 GET 请求。因此有人建议要实现另一种类型的请求(即DELETE),我必须使用AJAX。所以,我发现你可以使用Rails.ajax(...) 来执行异步javascript。但是当我添加以下代码时,我得到了错误:friends:22 Uncaught (in promise) ReferenceError: Rails is not defined

//dir: project-name/app/views/friends/index.html.erb
Swal.fire(
  "Good job!",
  "You clicked the button!",
  "success"
)
Rails.ajax(
  type: "GET",
  url: "<%= home_about_path %>",
  success: function(response) alert("succes Go to About Page") ,
  error: function(response) alert("error :" + response) 
);

因此,我在 project-name/app/javascript/packs/application.js 内部测试了 Rails.ajax(..),其中声明了 Rails!当然下面的代码会导致无限循环。但这只是为了测试目的!它工作正常。该页面一次又一次地重定向到关于页面。

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
Turbolinks.start()
ActiveStorage.start()

Rails.ajax(
  type: 'GET',
  url: '/home/about',
  success: function(response) location.pathname = "/home/about" ,
  error: function(response) alert('error delete' + response) 
);

所以我的问题是为什么命令Rails.ajax() 会在它声明的地方工作,而不是在特定的页面/控制器上?如何告诉 Rails 向整个系统声明 Rails var?


@Joel_Blum 的解决方案:

应用程序.js

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
Turbolinks.start()
ActiveStorage.start()

window.Rails = Rails;

index.html.erb:

Swal.fire(
  "Good job!",
  "You clicked the button!",
  "success"
)

var redirect = '<%= friends_path %>';
redirect += '/<%= friend.id %>';

Rails.ajax(
  type: 'DELETE',
  url: redirect,
  success: function(response) 
    //Friend has been deleted!
  ,
  error: function(response) 
    //Error with Ajax
    alert('error delete' + response) 
  
);

【问题讨论】:

这是因为您放置在视图中的javascript(称为内联javascript)没有被webpacker / assets pipeline 编译,它不知道您系统中的其他javascript。 好的,我明白了,但是有没有办法连接这个。既然Rails是在系统某处声明的,那么如何让内联JavaScript知道在哪里可以找到那个名字呢? 请记住,视图中的 javascript 不能使用 es6 语法或导入,通常最好不要经常这样做。您可以将所有 javascript 放在 application.js 中,只需注册一个 click 事件处理程序并在那里触发请求。 这是@max 建议的吗? 是的。您还可以通过 data-type="JSON" 将 Rails UJS 处理程序与其他请求类型(如 json)一起使用 【参考方案1】:

有几种方法可以解决这个问题。 您要问的基本上是如何使 Rails 对象成为全局对象,而不必使用模块导入。

import Rails from "@rails/ujs";
window.Rails = Rails;

应该照顾它或通过webpack as described in this answer

【讨论】:

感谢您的回答!现在工作得很好【参考方案2】:

要向 Rails 应用发送 DELETE 请求,您将发送:

使用 HTTP 方法 DELETE 的请求。现代浏览器在发送 XHR (ajax) 请求时可以做到这一点。 或带有参数_method=DELETE的POST请求。

如果您想在用户单击要setup an event handler 的元素时触发 ajax 调用。这应该在您的 application.js 中完成,而不是内联:

document.addEventListener('click', function(e)
  if (!e.target.matches('.my_special_button')) 
    return false;
  
  Rails.ajax(
    type: 'DELETE',
    url: '/home/about',
    success: function(response) location.pathname = "/home/about" ,
    error: function(response) alert('error delete' + response) 
  );
);

您的代码将在文件加载后立即触发 ajax 请求。

Rails UJS 允许您通过向按钮本身添加数据属性来发送 Ajax 请求。

<button data-remote="true" data-method="DELETE" data-url="/home/about">TEST</button>

然后您可以使用 js.erb 模板,该模板已评估并触发 当 ajax 请求完成时:

# app/views/pages/about.js.erb
Swal.fire(
  "Good job!",
  "You clicked the button!",
  "success"
)
location.pathname = "<%= home_about_path %>"; //redirect to About Page

Rails UJS 默认发送 Application/Javascript mime 类型的 ajax 请求。

或者使用 JSON 等其他类型并监听 Rails UJS ajax events:

<button data-remote="true" data-method="DELETE" data-url="/home/about" class="my_special_button">TEST</button>
document.addEventListener("ajax:success", (event) => 
   const [data, status, xhr] = event.detail;
   if (!e.target.matches('.my_special_button')) 
     return false;
   
   Swal.fire(
     "Good job!",
     "You clicked the button!",
     "success"
   )
   location.pathname = "/home/about";
);

【讨论】:

是的,你可以使用全局变量和内联 JS,但作为开发人员,你真的只是把事情弄得一团糟,耽误了自己的进步。

以上是关于如何使 Rails.ajax(...) 在所有页面上工作?的主要内容,如果未能解决你的问题,请参考以下文章

rails ajax URL更改

Rails 3.1 ajax:成功处理

Ruby on Rails AJAX文件上传

Rails.ajax 数据未传递给控制器

Rails - Ajax 与不显眼的 javascript Jquery UI 进度条

Rails/Ajax 在提交后将表单从创建更改为更新