用 Ruby on Rails 构建 JavaScript 应用后端:AJAX、数据传递与无侵入式 JavaScript 实战指南 📅 发布时间:2026/9/15 10:44:58 👁 浏览次数: 用 Ruby on Rails 构建 JavaScript 应用后端AJAX、数据传递与无侵入式 JavaScript 实战指南【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum导读当你已经掌握了大量客户端 JavaScript能让 HTML/CSS 页面里的各个组件对用户操作做出响应之后还缺最后一块拼图一个真正的后端。仅靠浏览器端代码应用会在页面刷新时忘记用户偏好和一切修改而 Local Storage 只能把数据存在用户当前这台电脑上同一用户换一台设备访问时应用什么都记不住。本文将以本仓库课程体系中的 using_rails_for_your_backend.md 为核心系统讲解如何用 Ruby on Rails 搭建可处理 JSON 请求的后端、如何通过 AJAX 让前端 JavaScript 与 Rails 通信以及无侵入式 JavaScriptunobtrusive JavaScript与数据传递的最佳实践。学完本篇你将能独立完成前端 JS Rails 后端的全栈应用如本仓库中 Wheres Waldo 照片标记游戏项目 所要求的架构。为什么前端应用需要一个真正的后端客户端存储的局限纯客户端 JavaScript 应用不是不能保存数据——localStorage就是浏览器提供的最常用方案。但它有两个天然局限数据随设备隔离localStorage只保存在用户当前访问页面的那台电脑上。同一个用户换一台设备、换一个浏览器数据就完全不在了。无法跨用户共享localStorage的数据是单用户、单浏览器维度的不可能实现排行榜多人协作这类需要服务器统一管理的功能。所以当你需要应用记住用户的任何状态登录信息、游戏成绩、用户生成的内容并且希望这些状态能被同一用户从不同设备访问、或被多个用户共享时你就需要把数据放到服务器上——也就是需要一个真正的后端。Rails 作为后端的选择在 using_rails_for_your_backend.md 中课程给出的方案非常直接既然你已经在本仓库的 full-stack Ruby on Rails 路径中学过 Rails那么下一步就是用 Rails 自己搭建后端。关键前置知识是 apis_and_building_your_own.md 中讲解的如何搭建一个能处理 JSON 请求的 Rails 后端——这篇文章将在下一节为你完整展开。从架构上看你的 Rails 应用本来就是一个 API浏览器本身也是一个程序每次请求页面本质上都是在向 Rails 发起 API 请求只不过 HTML 是最常见的默认响应类型。当你想直接拿数据而不是整张页面时只需要让同一个 URL 按请求格式返回 JSON 或 XML 即可见 apis_and_building_your_own.md。第一步让 Rails 控制器返回 JSON用扩展名区分请求格式Rails 根据请求文件扩展名如example.xml、example.json判断用户想要什么格式。你可以在服务器日志中确认 Rails 认为你在请求什么Started GET /posts/new for 127.0.0.1 at 2013-12-02 15:21:08 -0800 Processing by PostsController#new as HTML而请求/posts.json时Started GET /posts.json for 127.0.0.1 at 2013-12-04 12:02:01 -0800 Processing by PostsController#index as JSON第一行是请求的 URL第二行说明请求被分发到哪个控制器动作、以什么格式处理。同一个控制器动作完全可以根据请求类型返回不同内容——浏览器正常请求返回 HTML命令行或 JS 发起的 API 调用返回 JSON。用 respond_to 渲染 JSON 或 XML告诉控制器对 JSON/XML 请求返回对应格式的标准方式是#respond_to方法class UsersController ApplicationController def index users User.all respond_to do |format| format.html # index.html.erb format.xml { render :xml users } format.json { render :json users } end end end#respond_to把格式对象传给块你在上面挂接对应的渲染调用。什么都不写时HTML 会走默认模板这里是app/views/users/index.html.erb。#render足够聪明传入:json键时会对值调用#to_json把 Ruby 对象序列化成 JSON 字符串返回给请求方详见 apis_and_building_your_own.md。控制返回哪些属性as_json默认情况下User.all会被完整序列化包括 email 等敏感字段。为了只返回你想暴露的属性课程给出的经典做法是覆写模型上的#as_json方法# app/models/user.rb class User ActiveRecord::Base # Option 1: Purely overriding the #as_json method def as_json(_options{}) { :name self.name } # NOT including the email field end # Option 2: Working with the default #as_json method def as_json(options{}) super({ only: [:name] }.merge(options)) end end背后原理也是本仓库课程的知识点#to_json做两件事——先运行#as_json拿到需要渲染成 JSON 的属性哈希再用ActiveSupport::json.encode真正执行序列化。所以修改#as_json比整体覆写#to_json更精准能保留默认渲染行为并叠加你的筛选见 apis_and_building_your_own.md。控制器端可以简化成总是返回 JSON# app/controllers/users_controller.rb class UsersController ApplicationController def index render :json User.all end end注意用#render时不需要自己调用#to_json框架会代劳。只返回错误码head有时你只想发一个不带响应体的 HTTP 错误码# app/controllers/users_controller.rb class UsersController ApplicationController def index head :not_found end end这是 Rails Guides 中用head构建只含头部的响应的典型用法适合做 AJAX 校验失败、资源不存在等场景的轻量响应见 apis_and_building_your_own.md。外部访问的认证与 API Token如果只想让已登录用户调用 API现有的控制器认证如before_action :require_login同样适用——你不希望未登录用户能通过 API 拿敏感数据正如不希望他们访问未授权的 HTML 页面。但当请求方不是浏览器比如命令行、其他应用时无法依赖浏览器 cookie 做认证因此大多数 API 会给每个授权用户签发专属 token随请求一起发送作为认证凭证见 apis_and_building_your_own.md。第二步无侵入式 JavaScriptUnobtrusive JavaScript概念与原理无侵入式 JavaScript是 Rails 处理前端脚本的核心哲学把 JavaScript 行为与 HTML 结构分离脚本通过data-*属性、约定好的 class 或 ID 挂接行为而不是把onclick之类的内联事件处理器直接写进 HTML。这样 HTML 保持干净、可读行为可复用也更容易维护。仓库中的 turbo_drive.md 和 stimulus_js.md 就是这套哲学的现代体现TurboHotwire 的一部分默认随 Rails 发布运行在浏览器中。Turbo Drive 监听用户点击链接、提交表单代为发起请求并不经过整页刷新地更新页面。它通过扫描a标签上的data-turbo-method等属性改变请求方法如DELETE通过data: { turbo_action: replace }控制浏览器历史行为见 turbo_drive.md。Stimulus一个HTML first的小框架用data-controller、data-target、data-action三个核心属性把行为挂到现有 HTML 上而不是渲染 HTML。比如div>!-- app/views/games/show.html.erb -- script typeapplication/json idgame-data% game.to_json.html_safe %/script然后在 JavaScript 里解析这个script typeapplication/json标签的内容const gameData JSON.parse(document.getElementById(game-data).textContent);要点在于用typeapplication/json的 script 标签而不是普通typetext/javascript浏览器不会把它当作可执行脚本执行天然规避了直接拼接 JS 的注入风险序列化时配合上文的as_json只暴露必要字段避免把敏感数据如 email、password_digest带到前端对于大量数据避免在页面 HTML 里内联渲染而是通过 AJAX 按需拉取见下文。CSRF Token 的处理如果你用 JavaScript如fetch发起非 GET 请求POST/PATCH/DELETERails 会校验 CSRF Token否则会报 Warning, cant verify CSRF token authenticity。课程Additional Resources中专门收集了两篇 Stack Overflow 方案见 using_rails_for_your_backend.md最常用的做法是从页面 meta 标签读取 token 并放进请求头!-- app/views/layouts/application.html.erb -- % csrf_meta_tags %// fetch 非 GET 请求时带上 token fetch(/api/games, { method: POST, headers: { Content-Type: application/json, X-CSRF-Token: document.querySelector(meta[namecsrf-token]).getAttribute(content) }, body: JSON.stringify(data) });Rails 7 中配合 importmap.md 或 js_bundling.md 搭建的前端环境这一模式是前后端联调的基础。第四步用 AJAX 加载大数据为什么用 AJAX 加载大批量数据学习成果清单中的第三个问题是为什么应该用 AJAX 加载大批量数据见 using_rails_for_your_backend.md。答案可以概括为三点首屏更快页面初始 HTML 不携带大批量数据用户看到可交互界面的时间更短按需加载数据真正需要时才发起异步请求页面滚动到某处、用户点击某个功能时减少无用传输体验更顺滑AJAX 是不经过整页刷新、用 JavaScript 向服务器发起的异步 HTTP 请求这一表述也出现在仓库 react_and_the_backend/using_ruby_on_rails_for_your_backend.md 中请求期间页面不卡顿数据到位后用 JavaScript 局部更新 DOM。实现上前端用fetchAPI 请求 Rails 返回 JSON 的端点拿到数据后渲染。你可以先用简单的fetch(/users.json)验证链路再逐步封装错误处理、加载状态等。Rails 7 下前端 JavaScript 的托管方式课程作业第 1 条要求阅读 Daniel Kehoe 关于 Using JavaScript in your Rails App 的教程其中涉及依赖管理的大量内容。在当代 Rails 中这部分已经演进为两条主流路线本仓库课程均有专门章节Import mapsRails 7 默认importmap-rails是 Rails 7 默认的 JavaScript 管理方案用逻辑名把 ES Module 库映射到带版本/摘要的文件直接从浏览器加载无需转译和打包也就不再需要 Webpack、Yarn、npm见 importmap.md。HTTP/2 时代多小文件传输不再是性能问题而且缓存粒度更细——只改动被修改的那一个文件。config/importmap.rb中的pin就是裸模块标识符如import React from react的字符串替换# config/importmap.rb pin react, to: https://ga.jspm.io/npm:react18.2.0/index.js也可以让./bin/importmap命令从 CDN 下载并 vendor 依赖$ ./bin/importmap pin react react-dom Pinning react to vendor/javascript/react.js via download from https://ga.jspm.io/npm:react18.2.0/index.js Pinning react-dom to vendor/javascript/react-dom.js via download from https://ga.jspm.io/npm:react-dom18.2.0/index.js产出的 pin 会写入config/importmap.rb包下载到vendor/javascript可通过资产管道引用不再需要的依赖用./bin/importmap unpin react移除见 importmap.md。JS Bundlingesbuild / rollup / webpack如果你需要真正的打包比如引入 React 等大型库、使用 JSX、需要 tree-shakingjsbundling-rails提供了 esbuild、rollup、webpack 三种安装器见 js_bundling.md。打包产物输出到app/assets/builds走标准资产管道。开发时运行yarn build --watch它会监听 JS 文件变化并持续重新打包配合另一个终端里的rails server使用。更省事的是./bin/dev一条命令同时启动yarn build --watch和rails server见 js_bundling.md。无论选哪条路线前端最终都是通过 AJAX 请求 Rails 的 JSON 端点——这正是本篇数据传递主题的落点。实战演练把前端 JavaScript 接到 Rails 后端结合 project_wheres_waldo_a_photo_tagging_app.md你可以用下面的路径完整演练一遍前端 JS Rails 后端创建最小 Rails 应用先用最精简的骨架把 HTML 页面跑起来该项目的第 3 步要求。先做前端后接后端先不调用任何后端接口纯 JavaScript 实现交互第 4 步点击照片弹出定位框和角色下拉菜单、点击别处收起。接通校验接口用户选择角色后向 Rails 后端发 AJAX 请求验证点击位置是否命中该角色由后端返回正确/错误第 5 步。串联完整流程选择角色 → 后端校验 → 正确则在地图上打标记错误则给出提示第 6 步。服务端计时与成绩该项目的关键设计是计时必须放在服务端否则用户可篡改分数——这正是数据放后端这一主题的绝佳例证。用户找齐所有角色后前端把用时提交给 Rails写入高分榜数据库第 7 步。这个项目把本文全部知识点串成一条线Rails 返回 JSON 的控制器含respond_to/render :json、安全地向前端传递初始数据、AJAX 请求含 CSRF Token、以及把成绩等状态持久化到后端。项目还给出了可选的扩展方向把多张图片加载进数据库让用户开局前自选图片见 project_wheres_waldo_a_photo_tagging_app.md。知识自检清单完成本篇学习后你应该能回答以下问题对应原文档的 Knowledge Check见 using_rails_for_your_backend.md如何在某个 Rails 视图页面加载自定义 JavaScript——用content_for :javascript在布局中预留区块并在对应视图模板中按需注入避免污染全局脚本。无侵入式 JavaScript如何工作——行为与 HTML 分离通过data-*属性挂接事件与控制器Rails 7 中典型体现是 Turbo 的data-turbo-method与 Stimulus 的data-controller/data-action。如何把数据从 Rails 应用传给 JavaScript——把 JSON 数据安全地 bootstrapping 进视图如script typeapplication/json标签或 meta 标签或通过 AJAX 按需拉取发起非 GET 请求时携带 CSRF Token。为什么要用 AJAX 加载大批量数据——加快首屏、按需加载、避免整页刷新带来的卡顿提升用户体验。总结把 Rails 变成 JavaScript 前端的后端本质上就是让控制器学会按请求格式吐出 JSON并围绕数据传递建立三条纪律用respond_to/render :json控制输出格式用as_json精确控制暴露字段用 AJAX 安全的 bootstrapping 让数据在前后端之间可靠流动。在这个基础上配合无侵入式 JavaScript 的思路与 Rails 7 的 import map / jsbundling 工具链你就能把前端 JS 交互 Rails 持久化后端的最后一环补全——正如课程所说你已经拥有拼齐 Web 开发最后几块拼图所需的一切。深入阅读仓库内apis_and_building_your_own.md构建 Rails API 的完整基础respond_to、as_json、head 错误响应、API token、SOAimportmap.mdRails 7 默认的 import map 方案与 pin 机制js_bundling.mdesbuild / rollup / webpack 打包路线turbo_drive.mdTurbo 如何让导航不再整页刷新stimulus_js.md用 data 属性增强 HTML 的 Stimulus 框架project_wheres_waldo_a_photo_tagging_app.md把本课知识落地的全栈实战项目【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考