Skip to content

Ruby on Rails - AJAX

Ruby on Rails - 使用 Hotwire/Turbo 的现代 AJAX

Section titled “Ruby on Rails - 使用 Hotwire/Turbo 的现代 AJAX”

AJAX (Asynchronous JavaScript and XML,异步 JavaScript 和 XML) 允许 Web 页面通过在后台与服务器交换少量数据来异步更新。这意味着可以在不重新加载整个页面的情况下更新 Web 页面的部分内容,从而带来更快、响应更流畅的用户体验。

AJAX 结合了多种技术:

  • HTML/XHTML 和 CSS 用于呈现。
  • 文档对象模型 (DOM) 用于动态显示和交互。
  • JSON 或 XML 用于数据交换(现在 JSON 更常用)。
  • fetch API 或 XMLHttpRequest 对象用于异步通信。
  • JavaScript 将这些技术结合在一起。

虽然传统的 AJAX 通常涉及编写大量 JavaScript 代码,但现代 Rails (7+) 推崇使用 Hotwire(主要是 Turbo 和 Stimulus)来以最少的自定义 JavaScript 代码实现类似效果。

Rails 如何使用 Turbo 实现异步操作

Section titled “Rails 如何使用 Turbo 实现异步操作”

Turbo 是 Hotwire 套件的一部分,它通过减少 JavaScript 代码的使用,使 Rails 应用更快、更具交互性。它通过拦截链接点击和表单提交,并异步处理它们来实现此功能。

一个典型的 Turbo 增强交互流程:

  • 触发: 用户点击链接或提交表单。
  • 请求: Turbo 拦截该动作并向服务器发出 AJAX 请求(使用 fetch)。
  • 服务器处理: Rails 控制器动作像往常一样处理请求。它不是返回一个完整的 HTML 页面,而是可以返回一个 HTML 片段或特定的 Turbo Stream 指令。
  • 客户端响应处理: - 如果返回的是完整的 HTML 页面,Turbo Drive 会智能地更新当前页面的 <body> 并合并 <head>,模拟一次完整的页面加载,但速度更快。 - 如果返回的是 Turbo Stream 指令,Turbo 会更新页面特定部分(例如,追加、前置、替换或移除元素),而无需进行完整的页面刷新。

这种方法通过利用服务器端渲染和约定,简化了动态界面的构建。

AJAX 示例:使用 Turbo Streams 删除项目

Section titled “AJAX 示例:使用 Turbo Streams 删除项目”

我们以一个示例来说明:使用 Turbo Streams 异步删除列表中的项目。我们假设您有一个 Pony 模型的脚手架(Scaffold)(字段:name:string, profession:string)。

步骤 1:生成脚手架 (如果尚未创建)

Section titled “步骤 1:生成脚手架 (如果尚未创建)”

如果您还没有,请创建一个 Pony 资源:

$ bin/rails generate scaffold Pony name:string profession:string
$ bin/rails db:migrate

这会创建 Pony 的模型、控制器、视图和路由。

打开 app/views/ponies/index.html.erb。脚手架可能已经为删除 Pony 生成了一个 button_to。我们需要确保它兼容 Turbo,并且每个 Pony 项目都有一个唯一的 DOM ID。

修改显示 Pony 的循环,将每个 Pony 包裹在一个带有 DOM ID 的元素中,并更新删除按钮:
<div id="ponies">
<% @ponies.each do |pony| %>
<%= content_tag :div, id: dom_id(pony) do %> <%# Use dom_id for unique ID %>
<%# 使用 dom_id 生成唯一的 ID %>
<p>
**Name:**
<%= pony.name %>
</p>
<p>
**Profession:**
<%= pony.profession %>
</p>
<%= link_to "Show this pony", pony %>
<%# The button_to for destroy usually comes with data-turbo-confirm %>
<%# Ensure method: :delete and data attributes are present %>
<%# 用于删除的 button_to 通常自带 data-turbo-confirm %>
<%# 确保 method: :delete 和 data 属性存在 %>
<%= button_to "Destroy this pony", pony, method: :delete, data: { turbo_confirm: "Are you sure?" } %>
<hr>
<% end %>
<% end %>
</div>
<%= link_to "New pony", new_pony_path %>

dom_id(pony) 辅助方法(例如,输出 pony_123)对于 Turbo Streams 定位正确元素至关重要。

步骤 3:更新控制器 (ponies_controller.rb)

Section titled “步骤 3:更新控制器 (ponies_controller.rb)”

修改 app/controllers/ponies_controller.rb 中的 destroy 动作以响应 Turbo Stream 请求:

# DELETE /ponies/1 or /ponies/1.json
def destroy
@pony = Pony.find(params[:id])
@pony.destroy
respond_to do |format|
format.html { redirect_to ponies_url, notice: "Pony was successfully destroyed." }
format.json { head :no_content }
format.turbo_stream # Add this line to respond to Turbo Stream requests
# 添加这一行以响应 Turbo Stream 请求
end
end

通过添加 format.turbo_stream,当请求格式是 turbo_stream 时,Rails 将查找 destroy.turbo_stream.erb 文件。

步骤 4:创建 Turbo Stream 视图 (destroy.turbo_stream.erb)

Section titled “步骤 4:创建 Turbo Stream 视图 (destroy.turbo_stream.erb)”

创建一个新文件 app/views/ponies/destroy.turbo_stream.erb,内容如下:

<%= turbo_stream.remove @pony %>
<%# Or equivalently: turbo_stream.remove dom_id(@pony) %>
<%# 或等效地:turbo_stream.remove dom_id(@pony) %>

此模板告诉 Turbo 找到一个具有与 @pony 对象对应的 DOM ID(例如,id="pony_123")的 HTML 元素,并将其从页面中移除。

  1. 启动 Rails 服务器:$ bin/rails server
  2. 打开浏览器并访问 http://localhost:3000/ponies。
  3. 如果您没有任何 Pony,点击“New pony”,填写详细信息(例如,Name: “Rainbow Dash”, Profession: “Weather Patrol”),然后点击“Create Pony”。您将被重定向到 Pony 的 show 页面。返回 Pony 列表 (/ponies)。
  4. 您应该在列表中看到您创建的 Pony。每个 Pony 条目将包含其名称、职业、“Show this pony”链接和“Destroy this pony”按钮。

现在,点击其中一个 Pony 的“Destroy this pony”按钮。

由于 data: { turbo_confirm: "Are you sure?" },您应该会看到一个确认对话框(例如,“Are you sure?”)。

点击“OK”。该 Pony 项目将从列表中消失,但页面不会完全重新加载。URL 将保持为 /ponies。这就是 Turbo Streams 的实际效果!

此示例展示了一种简单而强大的方法,使用 Hotwire/Turbo 增强 Rails 中的用户界面,通常可以替代需要更多自定义 JavaScript 的旧式 AJAX 模式。