Ubuntu 22.04上构建Ruby on Rails应用:完整指南与最佳实践

引言

Rails 是一个用 Ruby 编写的 Web 应用框架。它采用一种“固执己见”的开发方式,假设在共同目标下,一套约定俗成的规则最适合开发者。因此,Rails 提供了处理路由、有状态数据、资源管理等方面的约定,以提供大多数 Web 应用所需的基本功能。

Rails 遵循模型-视图-控制器(MVC)的架构模式,该架构将应用程序逻辑(位于模型中)与路由和应用程序信息的呈现分离。这种组织结构以及允许开发人员将代码提取到助手和局部视图中的其他约定,确保应用程序代码不会不必要地重复。

在本教程中,您将构建一个 Rails 应用程序,让用户可以发布关于鲨鱼及其行为的信息。该项目将作为未来应用开发的起点。

先决条件

要按照本教程进行操作,您需要:

  • 一台运行 Ubuntu 22.04 的本地机器或开发服务器。您的开发机器应具有一个具有管理权限的非 root 用户,并配置了 UFW 防火墙。有关如何设置的说明,请阅读我们的《Ubuntu 22.04 初始服务器设置》教程。
  • 在您的本地机器或开发服务器上安装 Node.js 和 npm。本教程使用 Node.js 版本 18.13.0 和 npm 版本 8.19.3。有关在 Ubuntu 22.04 上安装 Node.js 和 npm 的指导,请遵循《如何在 Ubuntu 22.04 上安装 Node.js》教程中“选项 2 — 使用 PPA 安装”部分的说明。
  • 在您的本地机器或开发服务器上安装 Ruby、rbenv 和 Rails,遵循《如何在 Ubuntu 22.04 上使用 rbenv 安装 Ruby on Rails》教程中的步骤 1-4。本教程使用 Ruby 3.2.0、rbenv 1.2.0-52 和 Rails 7.0.4。

安装了 Node.js、Ruby、rbenv 和 Rails 之后,您就可以为应用程序安装数据库了。

第一步 – 安装 SQLite3

在创建 Rails 鲨鱼应用之前,您需要一个数据库来存储用户数据。Rails 默认配置为使用 SQLite,这在开发中通常是一个不错的选择。由于应用数据不需要高级编程可扩展性,SQLite 将满足应用的需求。

首先,在您的终端内更新软件包索引:

apt update

接下来,安装 sqlite3libsqlite3-dev 包:

apt install sqlite3 libsqlite3-dev

这将安装 SQLite 及其所需的开发文件。

您可以检查版本来确认安装是否成功。

sqlite3 --version
输出
3.37.2 2022-01-06 13:25:41 872ba256cbf61d9290b571c0e6d82a20c224ca3ad82971edc46b29818d5dalt1

有了安装好的 SQLite,您就可以开始开发应用程序了。

第二步 – 创建一个新的 Rails 项目

安装数据库后,您可以使用 rails new 命令创建一个新的 Rails 项目,并访问 Rails 提供的一些默认样板代码。

使用以下命令创建一个名为 sharkapp 的项目:

rails new sharkapp

输出显示 Rails 为您的新项目创建的所有不同的事物。以下输出突出显示了一些重要的文件、目录和命令。

输出
创建 . . . 创建 Gemfile . . . 创建 app . . . 创建 app/controllers/application_controller.rb . . . 创建 app/models/application_record.rb . . . 创建 app/views/layouts/application.html.erb . . . 创建 config 创建 config/routes.rb 创建 config/application.rb . . . 创建 config/environments 创建 config/environments/development.rb 创建 config/environments/production.rb 创建 config/environments/test.rb . . . 创建 config/database.yml 创建 db 创建 db/seeds.rb . . . 运行 bundle install . . . Bundle complete! 15 Gemfile dependencies, 69 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. . . .

以下是一些已创建的 Rails 文件和文件夹的简要描述:

  • Gemfile: 此文件列出了应用程序的 gem 依赖项。Gem 是 Ruby 软件包,Gemfile 允许您管理项目的软件需求。
  • app: app 目录是您主要应用程序代码的存放位置。这包括构成应用程序本身的模型(models)、控制器(controllers)、视图(views)、资产(assets)、辅助方法(helpers)和邮件程序(mailers)。Rails 为您提供了一些应用程序级别的 MVC 模型样板文件,例如 app/models/application_record.rb、app/controllers/application_controller.rb 和 app/views/layouts/application.html.erb。
  • config: 此目录包含应用程序的配置设置:
    • config/routes.rb: 应用程序的路由声明位于此文件中。
    • config/application.rb: 应用程序组件的通用设置位于此文件中。
  • config/environments: 此目录是环境配置设置的存放位置。Rails 默认包含三个环境:开发(development)、生产(production)和测试(test)。
  • config/database.yml: 数据库配置设置位于此文件中,该文件分为四个部分:default、development、production 和 test。由于 `rails new` 命令附带的 Gemfile 中包含了 `sqlite3` gem,因此 `config/database.yml` 文件的 `adapter` 参数被设置为 `sqlite3`,这表明您将在此应用程序中使用 SQLite 数据库。
  • db: 此文件夹包含一个名为 `migrate` 的数据库迁移目录,以及 `schema.rb` 和 `seeds.rb` 文件。`schema.rb` 包含有关数据库的信息,而 `seeds.rb` 是您可以放置数据库种子数据的地方。

最后,Rails 运行 `bundle install` 命令来安装 Gemfile 中列出的依赖项。

一旦一切设置完成,导航到新的 `sharkapp` 目录。

cd sharkapp

在 `sharkapp` 目录中,使用 `rails server` 命令启动 Rails 服务器,以确保您的应用程序正常工作。如果您在本机上工作,请输入以下代码启动服务器:

rails server

Rails 默认绑定到本地主机,这意味着您可以通过在浏览器中导航至 `localhost:3000` 来访问您的应用程序。

Rails 默认着陆页。如果您正在使用开发服务器,请确保端口 3000 上允许连接。

sudo ufw allow 3000

然后使用 `–binding` 标志启动服务器,绑定到您的服务器 IP 地址。

rails server --binding=your_server_ip

在浏览器中导航至 `http://your_server_ip:3000` 以访问默认的 Rails 首页。

当您准备好了,可以通过在终端中按下 `CTRL+C` 来停止服务器。

当您的应用程序已经创建并就位时,您可以从 Rails 脚手架开始构建,以创建一个独特的应用程序。

步骤三 — 构建应用程序的脚手架

要创建鲨鱼应用程序,您需要创建一个模型来管理应用程序数据,视图以使用户可以与该数据进行交互,并创建一个控制器来管理模型和视图之间的通信。要构建这些内容,可以使用 `Rails generate scaffold` 命令。该命令将生成一个模型、一个用于更改数据库架构的数据库迁移、一个控制器以及一整套用于管理应用程序的创建、读取、更新和删除(CRUD)操作的视图,还包括用于局部视图(partials)、辅助方法(helpers)和测试(tests)的模板。

生成脚手架命令在底层执行了许多操作。该命令包括模型的名称以及您想要在数据库表中的字段。Rails 使用 Active Record 来管理应用数据之间的关系,构建为具有模型的对象,并存储在应用数据库中。这些模型是 Ruby 类,同时继承 `ActiveRecord::Base` 类。这意味着您可以像操作 Ruby 类一样操作自己的模型类。此外,还可以使用 Active Record 的方法。Active Record 确保每个类被映射到数据库中的一张表,每个类的实例被映射为该表中的一行。

运行以下命令生成一个 `Shark` 模型、控制器和相关视图:

rails generate scaffold Shark name:string facts:text

这个命令中的 `name:string` 和 `facts:text` 选项表示您在数据库表中创建的字段和它们应接受的数据类型。两者都允许您输入您想要的内容。`text` 选项允许更多的字符。

输入此命令后,输出显示生成的所有不同文件。

输出

这是文章《如何在Ubuntu 22.04上构建一个Ruby on Rails应用程序》的第3部分(共5部分)。

invoke active_record create db/migrate/20190804181822_create_sharks.rb
create app/models/shark.rb
. . .
invoke resource_route route resources :sharks
invoke scaffold_controller create app/controllers/sharks_controller.rb
invoke erb create app/views/sharks
create app/views/sharks/index.html.erb
create app/views/sharks/edit.html.erb
create app/views/sharks/show.html.erb
create app/views/sharks/new.html.erb
create app/views/sharks/_form.html.erb
. . .

Rails 在 app/models/shark.rb 中创建了模型,并生成了一个与之相关的数据库迁移文件:db/migrate/20190804181822_create_sharks.rb。请注意,迁移文件的时间戳可能与示例输出不同。

它还创建了一个控制器,命名为 app/controllers/sharks_controller.rb,并创建了与应用程序 CRUD(创建、读取、更新、删除)操作相关的视图,这些视图都存放在 app/views/sharks 目录下。其中包含一个局部视图 _form.html.erb,它包含了在各个视图中可重用的代码。

最后,Rails 在 config/routes.rb 中添加了一个新的资源路由 resources :sharks。这使得 Rails 路由器能够将传入的 HTTP 请求与 sharks 控制器及其关联的视图相匹配。

尽管 Rails 已经完成了大部分应用程序代码的构建工作,但值得深入研究一些文件,以更好地了解其内部机制。

要理解控制器文件,请在您的终端中输入以下命令:

cat app/controllers/sharks_controller.rb
输出
class SharksController < ApplicationController
  before_action :set_shark, only: %i[ show edit update destroy ]

  # GET /sharks or /sharks.json
  def index
    @sharks = Shark.all
  end

  # GET /sharks/1 or /sharks/1.json
  def show
  end

  # GET /sharks/new
  def new
    @shark = Shark.new
  end

  # GET /sharks/1/edit
  def edit
  end

  # POST /sharks or /sharks.json
  def create
    @shark = Shark.new(shark_params)

    respond_to do |format|
      if @shark.save
        format.html { redirect_to shark_url(@shark), notice: "Shark was successfully created." }
        format.json { render :show, status: :created, location: @shark }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @shark.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /sharks/1 or /sharks/1.json
  def update
    respond_to do |format|
      if @shark.update(shark_params)
        format.html { redirect_to shark_url(@shark), notice: "Shark was successfully updated." }
        format.json { render :show, status: :ok, location: @shark }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @shark.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /sharks/1 or /sharks/1.json
  def destroy
    @shark.destroy

    respond_to do |format|
      format.html { redirect_to sharks_url, notice: "Shark was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_shark
      @shark = Shark.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def shark_params
      params.require(:shark).permit(:name, :facts)
    end
end

控制器负责管理信息的获取和传递给其关联模型的方式,以及将其与特定视图关联的方式。例如,鲨鱼控制器包含一系列方法,大致映射到标准的创建、读取、更新和删除操作。还有更多方法可以提高在错误情况下的效率。

举个例子,考虑一下 create 方法:

~/sharkapp/app/controllers/sharks_controller.rb
. . .
  def create
    @shark = Shark.new(shark_params)

    respond_to do |format|
      if @shark.save
        format.html { redirect_to @shark, notice: 'Shark was successfully created.' }
        format.json { render :show, status: :created, location: @shark }
      else
        format.html { render :new }
        format.json { render json: @shark.errors, status: :unprocessable_entity }
      end
    end
  end
. . .

如果成功保存了 Shark 类的新实例,则 redirect_to 将生成一个新的请求,然后将其引导到控制器。这是一个 GET 请求,将由 show 方法处理,该方法将向用户显示他们最近添加的输入。

如果出现故障,Rails 会重新渲染 app/views/sharks/new.html.erb 模板,而不会向路由发送另一个请求,从而让用户有机会重新提交数据。

除了 sharks 控制器外,Rails 还为索引视图创建了一个模板,该模板映射到控制器中的 index 方法。您将使用此视图作为您的应用程序的根视图。

运行以下命令来输出文件:

cat app/views/sharks/index.html.erb
输出
<p style="color: green"><%= notice %></p>
<h1>Sharks</h1>
<div id="sharks">
  <% @sharks.each do |shark| %>
    <%= render shark %>
    <p>
      <%= link_to "Show this shark", shark %>
    </p>
  <% end %>
</div>
<%= link_to "New shark", new_shark_path %>

索引视图循环遍历 Shark 类的实例,该类映射到数据库中的 sharks 表。使用 ERB 模板,视图输出与每个独立的鲨鱼实例关联的表格中的每个字段:名称和事实。

然后视图使用 link_to 辅助函数来创建一个超链接,其中提供的字符串作为链接的文本,提供的路径作为目的地。这些路径本身是通过在 Rails generate scaffold 命令中定义鲨鱼资源路由时可用的辅助函数变得可能的。

使用新的视图,使用局部视图。运行以下命令来返回 app/views/sharks/new.html.erb 模板:

cat app/views/sharks/new.html.erb
输出

这是文章《如何在Ubuntu 22.04上构建一个Ruby on Rails应用程序》的第4部分(共5部分)。

内容片段:

<h1>新鲨鱼</h1>
<%= render "form", shark: @shark %>
<br>
<div>
  <%= link_to "返回鲨鱼列表", sharks_path %>
</div>

尽管这个模板上看起来似乎缺少一个新鲨鱼条目的输入字段,但对于渲染“表单”的引用表明该模板正在调用_form.html.erb的部分文件,该文件提取了在视图中重复出现的代码。

输出_form.html.erb文件以更全面地了解如何创建新的鲨鱼实例。

cat app/views/sharks/_form.html.erb
输出


<%= form_with(model: shark) do |form| %>
  <% if shark.errors.any? %>
    <div style="color: red">
      <h2><%= pluralize(shark.errors.count, "个错误") %> 阻止了此鲨鱼的保存:</h2>
      <ul>
        <% shark.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <div>
    <%= form.label :name, style: "display: block" %>
    <%= form.text_field :name %>
  </div>
  <div>
    <%= form.label :facts, style: "display: block" %>
    <%= form.text_area :facts %>
  </div>
  <div>
    <%= form.submit %>
  </div>
<% end %>

此模板使用form_with表单助手。表单助手旨在借助特定模型的字段和范围,方便用户通过输入创建新对象。在此示例中,form_with采用model: shark作为参数,并生成一个新的表单构建器对象,该对象的字段输入与sharks表中的字段对应。这意味着用户可以通过表单字段输入鲨鱼的名称和鲨鱼的相关信息。

提交此表单将创建一个JSON响应,其中包含用户数据,您的应用程序的其余部分可以通过params方法访问该数据。这将创建一个ActionController::Parameters对象。

既然您已经了解了Rails生成脚手架为您创建的内容,现在您可以继续设置应用程序的根视图。

第四步—创建应用程序根视图和测试功能。

理想情况下,您希望应用程序的登录页面与应用程序的根目录相匹配,这样用户就可以立即了解应用程序的目的。

例如,您可以创建一个欢迎控制器和一个相关的主页视图,为用户提供一个通用的登录页面,该页面还可以链接到应用程序的不同部分。

为了进行设置,您需要修改config/routes.rb中的路由设置,以指定应用程序的根目录。

使用nano或您喜欢的编辑器打开config/routes.rb文件进行编辑。

nano config/routes.rb

~/sharkapp/config/routes.rb的内容需要用中文进行简洁的转述。

Rails.application.routes.draw do
  resources :sharks
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
  # root "articles#index"
end

如果不设置其他更具体的内容,访问 http://localhost:3000http://your_server_ip:3000 将显示默认的 Rails 欢迎页面。

将应用程序的根视图映射到鲨鱼控制器的索引视图,通过取消 #root "articles#index" 行前的 # 并将 article 替换为 shark,可解除注释。

~/sharkapp/config/routes.rb的中文本地化改写如下:

~/鲨鱼应用程序/配置/routes.rb

Rails.application.routes.draw do
  resources :sharks

  root 'sharks#index'
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

编辑完成后保存文件并退出编辑器。如果使用nano编辑器退出文件,请按下CTRL+XY,然后按回车键。

现在,当用户导航到您的应用程序根目录时,他们进入了鲨鱼登录页面,而不是默认的Rails登录页面。此外,他们现在有机会创建新的鲨鱼条目,查看现有的条目,并编辑或删除给定的条目。

接下来,使用以下命令运行迁移。

rails db:migrate

这个结果证实了迁移。

输出

== 20230124215633 CreateSharks: migrating =====================================
-- create_table(:sharks) -> 0.0041s
== 20230124215633 CreateSharks: migrated (0.0045s) ============================

重新启动您的Rails服务器。如果您在本地工作,运行以下命令:

rails s

在开发服务器上运行:

rails s --binding=your_server_ip

如果您在本地工作,导航到localhost:3000;如果您在开发服务器上工作,导航到http://your_server_ip:3000,以访问您的新着陆页。

Application Landing Page

要创建一只新的鲨鱼,请点击“新鲨鱼”链接。该链接将带您进入鲨鱼/新建的路径。

Create New Shark

您可以添加一些信息来测试您的应用程序。在姓名字段中填写“大白鲨”,在事实字段中填写“吓人”。

Add Great White Shark

然后,点击“创建鲨鱼”按钮来创建鲨鱼。

这个按钮会将您导向展示路由,而这得益于 before_action 过滤器的设置,在 set_shark 方法中,它会获取您创建的鲨鱼的 id。

~/sharkapp/app/controllers/sharks_controller.rb的内容再用中文进行释义如下:

class SharksController < ApplicationController
  before_action :set_shark, only: %i[ show edit update destroy ]

  . . .
  # GET /sharks/1 or /sharks/1.json
  def show
  end

  . . .

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_shark
      @shark = Shark.find(params[:id])
    end
  . . .
Show Shark

您可以通过点击“修改此鲨鱼”来测试编辑功能。这将带您进入该鲨鱼的编辑界面。

Edit Shark

更新有关大白鲨的事实,将“吓人”改为“巨大”,然后点击更新鲨鱼。这将带您回到展示路由。

Updated Shark

最后,点击返回到鲨鱼页面会带您进入更新后的索引视图。

新索引视图

现在您已经测试了应用程序的基本功能,您可以添加一些验证和安全检查,以使所有内容更加安全。

第五步 — 添加验证

您的鲨鱼应用程序可以接受用户输入,但想象一下这样的情况:用户试图创建一个没有添加任何信息的鲨鱼,或者创建一个数据库中已经存在的鲨鱼条目。您可以通过为模型添加验证机制,在数据输入进入数据库之前对其进行检查。由于应用程序的逻辑位于其模型中,因此在此处验证数据输入是合适的。

请注意,本教程不包括编写验证测试的内容,但您可以通过查阅Rails文档来获取更多有关测试的信息。

如果您还没有停止服务器,请立即在终端中按下CTRL+C来停止服务器。

打开您的shark.rb模型文件。

nano app/models/shark.rb

目前,文件告诉我们,Shark类从ApplicationRecord继承,而ApplicationRecord又从ActiveRecord::Base继承。

~/sharkapp/app/models/shark.rb 的内容:

class Shark < ApplicationRecord
end

在名称字段中添加一些验证,以确认该字段已填写且输入是唯一的,以防止重复输入。

~/sharkapp/app/models/shark.rb 的以下内容:

class Shark < ApplicationRecord
  validates :name, presence: true, uniqueness: true
end

接下来,为事实字段添加验证,以确保它也被填写。

~/sharkapp/app/models/shark.rb 的内容:

class Shark < ApplicationRecord
  validates :name, presence: true, uniqueness: true
  validates :facts, presence: true
end

验证代码中的 validates :facts, presence: true 行与事实的独特性无关,而是与唯一的鲨鱼条目相关联进行验证。

完成后请保存并关闭文件。

再次使用 rails srails s --binding=your_server_ip 启动您的服务器,然后在 http://localhost:3000http://your_server_ip:3000 导航到您的应用程序的根目录。

点击“新鲨鱼”链接。在表格中,将“Great White”添加到名称字段,“Big Teeth”添加到事实字段,然后点击创建鲨鱼。在这种情况下会出现一个警告信息。

唯一性验证警告

为了检查其他验证,请点击“回到鲨鱼”返回主页,然后再次点击“新的鲨鱼”。在新的表格中,将“名字”字段输入为“虎鲨”,将“事实”字段留空。当您点击“创建鲨鱼”时,会输出以下警告:

事实存在性警告

有了这些变化,您的应用程序进行了一些验证,以确保保存到数据库中的数据的一致性。现在您可以关注于应用程序的用户,并定义谁可以修改应用程序数据。

步骤6 — 添加身份验证

有一些验证机制,您可以确保保存到数据库的数据是可靠的。但是对于用户呢?如果您不希望任何人都能向数据库中添加数据,那么您应该添加一些身份验证措施,以确保只有被允许的用户可以添加鲨鱼信息。为了实现这一点,可以使用 http_basic_authenticate_with 方法,该方法允许创建用户名和密码的组合来对用户进行身份验证。

在Rails中,有许多方法可以用于用户认证,包括使用 bcrypt 或 devise gem。但是,现在,向您的应用程序控制器添加一个方法,该方法将适用于应用程序中的各个操作。如果您将来添加更多控制器到应用程序中,这将非常有用。

使用 CTRL+C 停止您的服务器。

打开定义您的 ApplicationController 的文件。

nano app/controllers/application_controller.rb

这里是 ApplicationController 类的定义,您的应用程序中的其他控制器都继承自它。

~/sharkapp/app/controllers/application_controller.rb 的内容:

class ApplicationController < ActionController::Base
end

为了验证用户,使用带有 http_basic_authenticate_with 方法的硬编码用户名和密码。将以下代码添加到文件中。

~/sharkapp/app/controllers/application_controller.rb 的以下内容:

class ApplicationController < ActionController::Base
  http_basic_authenticate_with name: 'sammy', password: 'shark', except: [:index, :show]
end

除了在这里提供用户名和密码之外,您还通过指定不需要认证的路由来限制了认证:索引和展示。另一种实现方式是仅写:[:create, :update, :destroy]。这样,所有用户都将能够访问所有的鲨鱼,并阅读有关特定鲨鱼的信息。然而,当涉及修改网站内容时,用户将需要证明他们有访问权限。

在一个更健壮的设置中,您不会想以这种方式硬编码数值,但这个示例展示了如何为应用的路由包括身份验证。Rails默认将会话数据存储在 cookies 中:一旦您在特定操作上进行身份验证,您在同一会话中将不需要再次进行身份验证。

在编辑完之后,保存并关闭 app/controllers/application_controller.rb 文件。现在,您可以测试身份验证功能了。

使用 rails srails s --binding=your_server_ip 启动服务器,并在 http://localhost:3000http://your_server_ip:3000 上访问您的应用程序。

在登录页面上,点击“新建鲨鱼”按钮。这将触发以下认证窗口。

用户认证

如果您输入的用户名是 sammy,密码是 shark,并且这是您添加到 app/controllers/application_controller.rb 的组合,您将能够安全地创建一个新的鲨鱼。

您现在拥有一个完美运行的鲨鱼应用,包括数据验证和基本的认证方案。

结论

在本教程中创建的Rails应用程序是一个可以用于进一步开发的起点。如果您对探索Rails生态系统感兴趣,项目文档是一个很好的开始地点。

您还可以通过阅读《如何为Ruby on Rails应用程序创建嵌套资源》来了解更多关于将嵌套资源添加到您的项目中的知识,这篇文章将向您展示如何构建应用程序的模型和路由。

此外,您可能想要尝试使用 React 等框架来为您的项目设置更强大的前端。《如何使用React前端设置Ruby on Rails项目》提供了关于如何实现这个目标的指导。

如果您想探索不同的数据库选项,您也可以查阅《如何在Ubuntu 20.04上使用PostgreSQL与Ruby on Rails应用程序》,其中介绍了如何使用 PostgreSQL 而不是 SQLite。您还可以查阅我们的 PostgreSQL 教程库,以了解更多关于使用这个数据库的内容。

bannerAds