ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Rails Girls 指南:为你的 Rails 应用添加评论功能(Commenting)

Rails Girls 指南:为你的 Rails 应用添加评论功能(Commenting) 教程后端【免费下载链接】guides.railsgirls.comRails Girls Guides项目地址https://gitcode.com/gh_mirrors/gu/guides.railsgirls.com点击查看免费下载本篇指南Rails Girls Guides 系列的第 12 篇源文档位于 _pages/commenting.md手把手教你基于已经建好的railsgirls应用Idea 应用从零添加评论功能让访问者可以在每条 idea 下留言、查看留言并删除留言。与之前大量依赖rails generate scaffold的步骤不同本篇将更多地手写 Ruby 代码让你深入理解 Rails 的路由嵌套、模型关联、控制器与视图之间的协作方式。读完本篇你将掌握嵌套资源路由的写法、一对多模型关联的建立、以及用form_with快速实现表单提交的完整链路。在动手之前请确保你已经按顺序完成了前面的主指南从 _pages/start.md 到 _pages/design.md特别是已经创建好名为railsgirls的应用、生成了 Idea 的 scaffold 并完成了数据库迁移。该指南的定位信息可以在 主指南索引 中看到——它在指南列表中位列第 12 项紧跟在样式设计指南之后、图片缩略图与 RSpec 测试指南之前是应用功能完善阶段的重要一环。理解目标评论到底是什么评论Comment是访客在网站上留下的短消息。在本应用中我们要实现的目标非常具体每条idea可以拥有多条comment每条comment必须属于某一条特定的idea评论显示在对应 idea 的详情页上不会串页——不同 idea 的评论互不干扰访客可以提交新评论也可以删除评论。关键点在于评论与 idea 之间是典型的一对多one-to-many关系。一个 Idea 可以有很多评论但一条评论只能属于一个 Idea。整个实现围绕这条关系展开从数据库结构到路由、模型、控制器、视图层层递进。第一步为评论添加嵌套路由路由routes是 Rails 应用收到 HTTP 请求后分发的第一站。要让系统知道评论这个资源的存在我们需要修改config/routes.rb。打开该文件找到当前只有一行资源声明的部分resources :ideas将其替换为嵌套资源的写法resources :ideas do resources :comments end为什么使用嵌套路由把resources :comments放进resources :ideas的块里Rails 会生成一组嵌套在 idea 之下的评论路由。这样URL 本身就携带了归属信息例如GET /ideas/1/comments—— 列出 idea 1 的所有评论POST /ideas/1/comments—— 为 idea 1 创建一条评论DELETE /ideas/1/comments/5—— 删除 idea 1 下 id 为 5 的评论。从路由中我们就能直接推导出这条评论属于哪条 idea而不需要额外的查询参数。这也让控制器代码可以干净地通过params[:idea_id]拿到父资源的主键。第二步生成 Comment 模型与数据库迁移接下来创建评论的数据模型。注意这次不使用 scaffold——scaffold 会连带生成控制器、视图和一大堆样板代码而本指南的目标是减少对生成代码的依赖、亲手写 Ruby 代码。在终端执行rails generate model comment user_name:string body:text idea:references这条命令做了三件事创建一个名为Comment的模型对应app/models/comment.rb声明两个内容字段user_name字符串类型记录留言者姓名和body文本类型存放留言正文通过idea:references在评论表中加入idea_id外键字段告诉数据库这条评论属于哪条 idea——这正是评论不会显示在错误页面上的根基。执行迁移生成器同时会创建一个迁移文件位于db/migrate/目录下它的作用是让数据库知道新增了一张 comments 表。执行迁移命令使数据库结构真正生效rails db:migrate迁移完成后comments 表就真实存在于数据库中了包含user_name、body、idea_id以及 Rails 自动添加的created_at/updated_at时间戳字段。第三步打通模型之间的关联数据库层面有了idea_id但应用代码还需要显式声明两个模型之间的关系Rails 才知道如何帮你查询某条 idea 下的所有评论。Idea 端一条 idea 拥有很多评论打开app/models/idea.rb在class Idea ApplicationRecord这一行下面添加class Idea ApplicationRecord has_many :comments endhas_many :comments告诉 Rails一个 Idea 对象可以关联多条 Comment 记录。加上这一行之后你就可以直接在代码里写idea.comments来取出属于这条 idea 的全部评论——Rails 会自动生成对应的数据库查询。Comment 端一条评论属于一条 idea打开app/models/comment.rb你会看到生成器已经自动写好了归属关系class Comment ApplicationRecord belongs_to :idea endbelongs_to :idea引用了Idea模型它是我们之前生成模型时idea:references这一参数自动产出的结果。这一行与has_many :comments互为镜像共同构成了 Rails 中一对多关联的标准写法。第四步从数据库加载评论到详情页评论数据要被页面展示第一步是把它从数据库捞出来。在 Rails 的 MVC 架构中这个职责由控制器承担。打开app/controllers/ideas_controller.rb找到show方法。这是一个 Ruby 方法它的职责是从数据库加载数据、供视图我们之前编辑过的 HTML 文件使用。把原来的show方法修改为def show comments idea.comments end注意这里我们直接调用了idea.comments正是上一步has_many :comments声明带来的魔法——Rails 会根据关联关系自动查询出所有idea_id等于当前 idea 主键的评论记录并存入comments实例变量。之后视图就能通过comments访问这些数据了。第五步编写 CommentsController要把评论存进数据库之后还要能删除它们我们需要一个专门的控制器。和IdeasController一样它负责执行针对评论表的数据库操作。在app/controllers/目录下新建一个名为comments_controller.rb的文件macOS / Linux 使用touch app/controllers/comments_controller.rbWindows 使用ni app/controllers/comments_controller.rb打开这个空文件粘贴以下代码class CommentsController ApplicationController before_action :set_idea, only: %i[create destroy] before_action :set_comment, only: %i[destroy] def create comment idea.comments.new(comment_params) if comment.save redirect_to idea_path(idea), notice: Comment was successfully created. else render :new, status: :unprocessable_entity end end def destroy comment.destroy redirect_to idea_path(idea), notice: Comment was successfully destroyed. end private def set_idea idea Idea.find(params[:idea_id]) end def set_comment comment idea.comments.find(params[:id]) end def comment_params params.require(:comment).permit(:user_name, :body) end end逐段解读控制器before_action :set_idea, only: %i[create destroy]在create和destroy动作执行之前先从params[:idea_id]找到对应的 Idea 对象存入idea。由于路由是嵌套的请求 URL 中天然带有idea_id参数。before_action :set_comment, only: %i[destroy]在删除动作前通过idea.comments.find(params[:id])精确取出属于该 idea 的评论——注意是通过关联查找而非直接Comment.find这样即使有人篡改 URL 中的 id也无法删除不属于该 idea 的评论。create用idea.comments.new(comment_params)基于当前 idea 构建一条新评论自动填好idea_id保存成功则带着绿色提示信息重定向回 idea 详情页保存失败例如字段校验未通过则返回422 Unprocessable Entity状态码并重新渲染表单。destroy删除评论后重定向回 idea 详情页并显示删除成功提示。comment_params这是 Rails 的**强参数Strong Parameters**机制只允许:user_name和:body两个字段通过表单提交进入模型防止恶意用户注入其他字段。整个控制器只监听两类请求创建评论和删除评论。收到请求后它告诉数据库存什么、删什么然后把浏览器重定向回来源页面。教练小贴士这一部分非常适合由现场教练coach展开讲解控制器如何与 HTTP 请求、模型、视图三者交互一次完整的浏览器发请求 → 路由分发 → 控制器处理 → 模型读写数据库 → 视图渲染 HTML → 浏览器显示链路是怎样的。Rails Girls 的指南在网页端通过{% coach %}标签渲染为醒目的教练提示框该标签的实现可以在 _plugins/coach.rb 中看到。第六步在 idea 详情页展示评论现在数据已经能加载到comments接下来把它们显示在页面上。打开app/views/ideas/show.html.erb在文件最底部追加以下代码h2Comments/h2 % if comments.any? % % comments.each do |comment| % div pstrong% comment.user_name %/strong/p p% comment.body %/p % button_to Destroy this comment, idea_comment_path(idea, comment), method: :delete, class: btn btn-danger, form: { data: { turbo_confirm: Are you sure? } } % /div % end % % else % pNo comments found./p % end % h2Add a new comment/h2 % render partial: comments/form, locals: { idea: idea } %这段 ERB 代码做了四件事用comments.any?判断是否存在评论存在则循环渲染每一条每条评论显示留言者姓名comment.user_name加粗和正文comment.body用button_to生成一个删除按钮指向idea_comment_path(idea, comment)即嵌套路由中的删除 URL以DELETE方法提交并带上 Bootstrap 的危险按钮样式与 Turbo 确认弹窗turbo_confirm最后两行渲染一个评论提交表单——这是我们下一步要创建的内容。第七步创建评论提交表单要让访客能提交评论我们需要一个表单。在app/views/下新建comments/目录并在其中创建名为_form.html.erb的局部模板partialmacOS / Linux 使用mkdir -p app/views/comments/ touch app/views/comments/_form.html.erbWindows 使用md app/views/comments/ ni app/views/comments/_form.html.erb在新文件中粘贴以下代码% form_with(model: [idea, idea.comments.build]) do |form| % div classmb-3 % form.label :user_name, Your name, class: form-label % % form.text_field :user_name, class: form-control % /div div classmb-3 % form.label :body, Comment message, class: form-label % % form.text_area :body, class: form-control % /div % form.submit class: btn btn-primary % % end %表单的要点form_with(model: [idea, idea.comments.build])这是 Rails 6 时代的表单构造方式。传入的数组[idea, idea.comments.build]让 Rails 自动推导出提交地址——因为 idea 是已存在资源、comment 是新建对象它会自动指向嵌套路由POST /ideas/:idea_id/comments。idea.comments.build会基于当前 idea 构建一个内存中的空评论对象用于表单字段的绑定。form.text_field :user_name与form.text_area :body分别渲染姓名输入框和正文多行文本框并带有 Bootstrap 的form-label/form-control样式类。form.submit渲染提交按钮按钮文字默认显示为 Create comment。验证成果保存所有文件后刷新浏览器打开任意 idea 的详情页你应该能看到页面底部出现 Add a new comment 区域和完整的表单填入姓名和留言内容点击 Create comment 按钮页面顶部以绿色文字提示 Comment was successfully created.新评论出现在 Comments 区块中。再访问另一条不同 idea 的详情页你会发现刚才的评论不会出现在那里——这正是嵌套路由、idea_id外键和has_many/belongs_to关联共同作用的结果。回顾我们亲手写出了什么至此评论功能全部完成。回顾整个实现我们通过手写代码而非 scaffold 完成了三层工作层次文件职责路由config/routes.rb声明resources :comments嵌套于resources :ideas之下让 URL 携带归属信息模型app/models/idea.rb/app/models/comment.rbhas_many :comments与belongs_to :idea构成一对多关联数据库db/migrate/迁移文件通过idea:references建立idea_id外键控制器app/controllers/comments_controller.rb处理评论的创建与删除配合强参数过滤视图app/views/ideas/show.html.erbapp/views/comments/_form.html.erb展示评论列表、删除按钮与提交表单与之前使用rails generate scaffold idea ...的指南见 _pages/app.md相比本篇刻意减少了生成器的使用模型由你亲自生成并理解字段含义控制器完全手写视图手动拼接。这种少脚手架、多手写的方式能让你更清晰地看到 MVC 各个部件的真实协作方式——这恰恰是 Rails Girls 系列指南希望传递的核心价值理解比魔法更重要。如果你还想继续深入指南列表中接下来的两篇非常值得学习_pages/thumbnails.md为图片上传生成缩略图和 _pages/testing-rspec.md用 RSpec 为应用编写测试。赞分享教程后端【免费下载链接】guides.railsgirls.comRails Girls Guides项目地址https://gitcode.com/gh_mirrors/gu/guides.railsgirls.com点击查看免费下载相关推荐Arya在线Markdown编辑器揭秘免费专业写作工具的六大核心功能Arya在线Markdown编辑器揭秘免费专业写作工具的六大核心功能 在数字化写作日益普及的今天Arya作为一款基于Vue2和Vditor构建的免费在线Ma前端富文本Agent Starter Pack 安装指南四种安装方式、升级卸载与故障排查全解Agent Starter Pack 安装指南四种安装方式、升级卸载与故障排查全解 Agent Starter Pack 是一套用于在 Google Clou教程后端Ransack快速入门5个步骤为你的Rails应用添加搜索功能Ransack快速入门5个步骤为你的Rails应用添加搜索功能 想要为你的Ruby on Rails应用添加强大的搜索功能吗Ransack正是你需要的终极解后端搜索引擎上一篇FerretDB v1.8.0 发布解析$group 表达式、$expr 查询操作符与 SQLite 后端改进下一篇EMQX MQTT 桥接 $queue/ 订阅消息丢失修复Subscription-Identifier 在 MQ 投递链路中的完整解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表