Rails (零基础向)Ruby on Rails 从零搭建一个 Blog

brooke · 2024年06月27日 · 最后由 KAITHY 回复于 2024年06月29日 · 353 次阅读

重点概念

MVC

首先得了解 MVC 是什么东西,即 M(Model,模型)V(View,视图)C(Controller,控制器)。接下来从一个完整的 Ruby on Rails(ror) 项目流程来了解三者之间的关系。

  • 请求到达控制器:用户发送 HTTP 请求,请求被路由系统分发给相应的控制器动作。

  • 控制器处理请求:控制器接收请求,可能会从模型中获取数据,或者对模型进行操作。

  • 数据传递给视图:控制器通过实例变量将获取到的数据传递给视图。

  • 视图渲染响应:视图使用嵌入 Ruby 代码的 ERB 模板,将控制器传递的数据渲染成最终的 HTML 响应。

  • 响应返回给用户:最终生成的 HTML 响应由 Rails 框架发送给用户的浏览器,用户在浏览器中看到相应的页面或者数据。

由上面可知,模型负责和数据库做对接操作,控制器则负责从模型当中获取需要数据,视图则是负责对拿到的数据进行渲染。

Console

在 Ruby on Rails 中,console(控制台)指的是一个命令行工具,通常称为 Rails 控制台或 Rails 命令行控制台。它提供了一个交互式的环境,允许开发者在不启动完整的 Rails 应用程序的情况下,执行 Ruby 代码和与应用程序进行交互。

项目常用命令

创建一个新的 ror 项目

rails new <PROJECT-NAME>

开启新的服务

bin/rails server
rails server

创建 controller

bin/rails generate controller <CONTROLLER-NAME> index --skip-routes

创建 model

bin/rails generate model <MODEL-NAME> <DB-FIELD>

和 console 进行交互

bin/rails console

Blog 项目实践

首先运行

rails new blog

来创建一个名为 blog 的 ror 项目,接下去进入到 blog 目录 cd blog 。如果成功的话,运行 bin/rails server 之后,就可以访问到 http://localhost:3000/

博客文章至少需要两个部分的内容一个是标题 title 还有内容主题 body 。我们来创建有这两个部分的 model , 运行

bin/rails generate model Article title:string body:text

将创建一个 migrate文件 ,在 /db/migrate 下面。这个文件里的内容为

# 定义了一个名为 CreateArticles 的 Ruby 类,它继承自 ActiveRecord::Migration[7.1]。在 Rails 中,迁移类用于修改数据库结构,继承自 ActiveRecord::Migration 提供了一系列用于定义数据库迁移的方法和规范
class CreateArticles < ActiveRecord::Migration[7.1]
    # change 方法是 ActiveRecord::Migration 提供的一个特殊方法,用于定义要执行的数据库操作。在这个迁移中,change 方法内部包含了创建名为 articles 的新表格的指令
    def change
        # create_table 是 ActiveRecord::Migration 提供的方法之一,用于在数据库中创建新的表格。在这里,我们创建了一个名为 articles 的表格,do |t| 部分是一个代码块,用于定义表格的各个列和其属性
        create_table :articles do |t|
            t.string :title
            t.text :body

            t.timestamps
        end
    end
end

这段迁移代码的作用是创建一个名为 articles 的数据库表格,该表格具有 title(字符串类型)和 body(文本类型)两列,以及自动生成的 timestamps 列(用于记录创建和更新时间)。

博客项目肯定需要有增删改查操作,即增加文章,删除文章,修改文章,查找文章。将这四个功能写入到 app/controllers/articles_controller.rb 当中,就是

# 这行代码的核心作用是定义一个名为 ArticlesController 的控制器类,并使其继承自 ApplicationController,以便在 Rails 应用中处理和管理与文章相关的逻辑和请求
class ArticlesController < ApplicationController 
    # 获取所有文章并将它们存储在实例变量 @articles 中,以便在视图中显示所有文章列表
    def index 
        @articles = Article.all
    end

    # 根据传入的 params[:id] 查找特定 ID 的文章,并将其存储在实例变量 `@article` 中,以便在显示单个文章的视图中使用
    def show
        @article = Article.find(params[:id])
    end

    # 创建一个新的空白文章对象 `@article`,用于在创建新文章的表单页面中使用
    def new
        @article = Article.new
    end

    # 根据从表单收集的 article_params 创建新的文章对象,并尝试保存到数据库。如果保存成功,重定向到新创建的文章页面;如果保存失败,则重新渲染创建文章的表单页面,并返回状态码 422 Unprocessable Entity
    def create
        @article = Article.new(article_params)
        if @article.save
            redirect_to @article
        else
            render :new, status: :unprocessable_entity
        end
    end

    # 根据传入的 params[:id] 查找要编辑的文章,并将其存储在实例变量 `@article` 中,以便在编辑文章的表单页面中使用
    def edit
        @article = Article.find(params[:id])
    end

    # 根据传入的 params[:id] 查找要更新的文章,并根据从表单收集的 article_params 尝试更新。如果更新成功,则重定向到更新后的文章页面;如果更新失败,则重新渲染编辑文章的表单页面,并返回状态码 422 Unprocessable Entity
    def update
        @article = Article.find(params[:id])
        if @article.update(article_params)
            redirect_to @article
        else
            render :edit, status: :unprocessable_entity
        end
    end

    # 根据传入的 params[:id] 查找要删除的文章,并将其从数据库中删除。完成后重定向到根路径 (root_path),并返回状态码 303 See Other
    def destroy
        @article = Article.find(params[:id])
        @article.destroy

        redirect_to root_path, status: :see_other
    end

    # 定义了一个私有方法 article_params,用于过滤和允许 params 中的 article 参数,防止不必要的数据传递和安全问题
    private
    def article_params
        params.require(:article).permit(:title, :body)
    end
end

接下来就是视图部分,视图有四个文件 edit.html.erb, index.html.erb, new.html.erb, show.html.erb, 分别对应着编辑页面,首页,新建页面,展示页面。

  • edit.html.erb 用于编辑现有的文章。它预填充了现有文章的标题和正文内容,允许用户对这些内容进行修改,并提交表单以更新文章信息。
  • index.html.erb 用于展示文章列表和提供创建新文章的入口。
  • new.html.erb 用于创建新的文章。它包含了一个空的文章表单,用户可以填写标题和正文内容,并提交表单以创建新的文章。
  • show.html.erb 用于展示单篇文章的详细内容。它显示了文章的标题和正文,并提供了编辑和删除操作的链接。

接下来我将展示这四个部分的代码

# blog/models/views/articles/edit.html.erb
<h1>Edit Article</h1>
# 使用 form_with 方法生成一个表单,该表单与 @article 实例相关联,表示该表单用于编辑现有的文章对象
<%= form_with model: @article do |form| %>

# 在表单中显示文章标题的输入字段。使用 form.label 和 form.text_field 方法分别生成标题字段的标签和文本输入框。如果 @article 的标题验证失败(例如长度限制等),则会显示相应的错误消息(通过@article.errors.full_messages_for(:title) 迭代输出每个错误消息)
<div>
<%= form.label :title %><br>
<%= form.text_field :title %>
<% @article.errors.full_messages_for(:title).each do |message| %>
<div><%= message %></div>
<% end %>
</div>

# 在表单中显示文章正文的文本区域字段。类似于标题字段,使用 form.label 和 form.text_area 方法生成正文字段的标签和文本区域。如果 @article 的正文验证失败,将会显示相应的错误消息
<div>
<%= form.label :body %><br>
<%= form.text_area :body %><br>
<% @article.errors.full_messages_for(:body).each do |message| %>
<div><%= message %></div>
<% end %>
</div>

# 显示一个提交按钮,允许用户提交表单数据以更新文章的标题和正文内容
<div>
<%= form.submit %>
</div>
<% end %>
# blog/models/views/articles/index.html.erb

<h1>Articles</h1>

# 使用 <ul> 和 <li> 标签显示文章的列表。通过 <% @articles.each do |article| %> 循环遍历 @articles 实例变量中的每篇文章对象,对于每篇文章,使用 link_to 方法生成一个链接,链接到文章的详情页面(article_path(article)),显示文章的标题 article.title
<ul>
<% @articles.each do |article| %>
<li>
<%= link_to article.title, article %>
</li>
<% end %>
</ul>
<%= link_to "New Article", new_article_path %>
# blog/models/views/articles/new.html.erb
<h1>New Article</h1>

# 使用 `form_with` 方法生成一个表单,该表单与 `@article` 实例相关联,表示该表单用于创建一个新的文章对象
<%= form_with model: @article do |form| %>

# 在表单中显示文章标题的输入字段。使用 form.label 和 form.text_field 方法分别生成标题字段的标签和文本输入框。如果 @article 的标题验证失败(例如长度限制等),则会显示相应的错误消息(通过 @article.errors.full_messages_for(:title) 迭代输出每个错误消息)
<div>
<%= form.label :title %><br>
<%= form.text_field :title %>
<% @article.errors.full_messages_for(:title).each do |message| %>
<div><%= message %></div>
<% end %>
</div>

# 在表单中显示文章正文的文本区域字段。类似于标题字段,使用 form.label 和 form.text_area 方法生成正文字段的标签和文本区域。如果 @article 的正文验证失败,将会显示相应的错误消息
<div>
<%= form.label :body %><br>
<%= form.text_area :body %><br>
<% @article.errors.full_messages_for(:body).each do |message| %>
<div><%= message %></div>
<% end %>
</div>

# 表单提交
<div>
<%= form.submit %>
</div>

<% end %>
# blog/models/views/articles/show.html.erb
<h1><%= @article.title %></h1>
<p><%= @article.body %></p>
# 显示两个操作链接,一个是 "Edit" 编辑链接,另一个是 "Destroy" 删除链接
<ul>
# 使用 link_to 方法生成一个编辑链接,链接到编辑文章页面 (edit_article_path(@article))。用户点击这个链接可以进入编辑该文章的页面
<li><%= link_to "Edit", edit_article_path(@article) %></li>
# 使用 link_to 方法生成一个删除链接,链接到删除文章的路由路径 (article_path(@article))。同时,使用 data 选项传递了 turbo_method: :delete 表示这是一个通过 Turbo 框架发送的删除请求,并提供了 turbo_confirm 提示用户确认删除操作
<li><%= link_to "Destroy", article_path(@article), data: {
turbo_method: :delete,
turbo_confirm: "Are you sure?"
} %></li>
</ul>

反思

当然这些代码还有很多不足,包括但不限于对于 Controllerdestroy 部分,并没有添加如果操作失败的的错误打印等。

According to the forums I have reviewed, the five nights at freddy's offers a variety of entertaining ideas and insightful discoveries.

需要 登录 后方可回复, 如果你还没有账号请 注册新账号