引言
Rails 是一个用Ruby编写的Web应用程序框架。它采取了一种有主见的开发方法,假设在有共同目标的情况下,设定的惯例最能服务开发者。因此,Rails提供了处理路由、状态数据、资产管理等方面的约定,以提供大多数Web应用程序所需的基础功能。
Rails遵循模型-视图-控制器(MVC)架构模式,该模式将应用程序的逻辑(位于模型中)与信息的处理和展示分离开来。这种组织结构——以及其他允许开发者将代码提取到助手和局部视图的约定——确保了应用程序代码不会不必要的重复。
在本教程中,您将构建一个Rails应用程序,使用户能够发布有关鲨鱼及其行为的信息。这将是一个未来应用开发的良好起点。
前提条件
要学习本教程,您需要:
- 一台运行Ubuntu 18.04的本地机器或开发服务器。您的开发机器应具有拥有管理权限的非root用户,并配置了
ufw
防火墙。有关如何设置此配置的说明,请参阅我们的Ubuntu 18.04初始服务器设置教程。 - 在您的本地机器或开发服务器上安装了Node.js和npm。本教程使用Node.js版本10.16.3和npm版本6.9.0。有关在Ubuntu 18.04上安装Node.js和npm的指导,请遵循如何在Ubuntu 18.04上安装Node.js中“使用PPA安装”部分的说明。
- 在您的本地机器或开发服务器上安装 Ruby、rbenv 和 Rails,按照 如何在 Ubuntu 18.04 上使用 rbenv 安装 Ruby on Rails 中的步骤 1-4 进行操作。本教程使用 Ruby 2.5.1、rbenv 1.1.2 和 Rails 5.2.0。
步骤 1 — 安装 SQLite3
在创建我们的 Rails shark 应用程序之前,我们需要确保有一个数据库来存储用户数据。Rails 默认配置为使用 SQLite,这在开发中通常是一个不错的选择。由于我们的应用程序数据不需要高级别的编程扩展性,SQLite 将满足我们的需求。
首先,更新您的包索引:
接下来,安装 sqlite3
和 libsqlite3-dev
包:
sudo apt install sqlite3 libsqlite3-dev
这将安装 SQLite 及其所需的开发文件。
检查您的版本以确认安装成功:
Output3.22.0 2018-01-22 18:45:57 0c55d179733b46d8d0ba4d88e01a25e10677046ee3da1d5b1581e86726f2alt1
安装好 SQLite 后,您就可以开始开发您的应用程序了。
第二步 —— 创建一个新的 Rails 项目
安装好数据库后,我们可以创建一个新的 Rails 项目,并查看 Rails 通过 rails new
命令为我们提供的默认样板代码。
使用以下命令创建一个名为 sharkapp
的项目:
你将看到许多输出信息,告诉你 Rails 正在为你的新项目创建什么。下面的输出突出了一些重要的文件、目录和命令:
Output create
. . .
create Gemfile
. . .
create app
. . .
create app/controllers/application_controller.rb
. . .
create app/models/application_record.rb
. . .
create app/views/layouts/application.html.erb
. . .
create config
create config/routes.rb
create config/application.rb
. . .
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
. . .
create config/database.yml
create db
create db/seeds.rb
. . .
run bundle install
. . .
Bundle complete! 18 Gemfile dependencies, 78 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
. . .
* bin/rake: Spring inserted
* bin/rails: Spring inserted
这里高亮的输出告诉你,Rails 已经创建了以下内容:
Gemfile
:这个文件列出了你应用程序的 gem 依赖项。一个 gem 是一个 Ruby 软件包,而 Gemfile 允许你管理项目的软件需求。app
:app
目录是你主要应用程序代码的所在地。这包括构成应用程序本身的模型、控制器、视图、资产、辅助器和邮件程序。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
目录:
现在,您可以使用rails server
命令启动Rails服务器,以确保应用程序正常运行。如果您在本地机器上操作,请输入:
Rails默认绑定到localhost
,因此您现在可以通过在浏览器中导航至localhost:3000
来访问您的应用程序,您将看到以下图像:
如果您在开发服务器上工作,首先确保允许在端口3000
上进行连接:
然后使用--binding
标志启动服务器,绑定到您的服务器IP:
在浏览器中导航至http://your_server_ip:3000
,您将看到Rails的欢迎信息。
一旦你浏览完毕,可以通过按下 CTRL+C
来停止服务器。
应用创建并就位后,你就可以从 Rails 样板代码开始,构建一个独特的应用了。
第三步 — 搭建应用脚手架
为了创建我们的鲨鱼信息应用,我们需要创建一个模型来管理应用数据,视图来允许用户与这些数据交互,以及一个控制器来管理模型和视图之间的通信。为了构建这些组件,我们将使用 rails generate scaffold
命令,该命令将为我们提供一个模型、一个用于修改数据库模式的数据库迁移、一个控制器、一套完整的视图来管理应用的创建、读取、更新和删除(CRUD)操作,以及部分模板、助手和测试。
由于 generate scaffold
命令为我们做了大量工作,我们将仔细查看它创建的资源,以理解 Rails 在幕后所做的工作。
我们的 generate scaffold
命令将包含我们模型的名称以及我们希望数据库表中包含的字段。Rails 使用 Active Record 来管理应用程序数据(构建为具有模型的对象)与应用程序数据库之间的关系。我们的每个模型都是一个 Ruby 类,同时也继承自 ActiveRecord::Base
类。这意味着我们可以像操作 Ruby 类一样操作我们的模型类,同时还能引入 Active Record 的方法。Active Record 随后会确保每个类映射到数据库中的一个表,并且该类的每个实例映射到该表中的一行。
输入以下命令以生成一个 Shark
模型、控制器和相关视图:
通过 name:string
和 facts:text
,我们向 Rails 提供了关于我们希望数据库表中包含的字段及其应接受的数据类型的信息。两者都为我们提供了输入所需内容的余地,尽管 text
允许输入更多字符用于鲨鱼事实。
当你输入此命令时,你将再次看到一长串输出,解释 Rails 为你生成的所有内容。下面的输出突出了对我们设置较为重要的几个方面:
Output 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 已经为我们完成了应用程序代码的大部分构建工作,但查看一些文件以理解正在发生的事情仍然是有价值的。
首先,让我们通过以下命令查看控制器文件:
Outputclass SharksController < ApplicationController
before_action :set_shark, only: [:show, :edit, :update, :destroy]
# GET /sharks
# GET /sharks.json
def index
@sharks = Shark.all
end
# GET /sharks/1
# GET /sharks/1.json
def show
end
# GET /sharks/new
def new
@shark = Shark.new
end
# GET /sharks/1/edit
def edit
end
# POST /sharks
# POST /sharks.json
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
# PATCH/PUT /sharks/1
# PATCH/PUT /sharks/1.json
def update
respond_to do |format|
if @shark.update(shark_params)
format.html { redirect_to @shark, notice: 'Shark was successfully updated.' }
format.json { render :show, status: :ok, location: @shark }
else
format.html { render :edit }
format.json { render json: @shark.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sharks/1
# DELETE /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
# 使用回调函数在动作间共享通用设置或约束。
def set_shark
@shark = Shark.find(params[:id])
end
# 永远不要信任来自可怕互联网的参数,只允许白名单中的参数通过。
def shark_params
params.require(:shark).permit(:name, :facts)
end
end
控制器负责管理信息如何被获取并传递给其关联的模型,以及如何与特定的视图相关联。如你所见,我们的sharks
控制器包含了一系列方法,这些方法大致映射到标准的CRUD操作。然而,为了在出错时提高效率,这些方法比CRUD功能更多。
例如,考虑create
方法:
. . .
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
模板,而不是向路由器发出另一个请求,从而给用户再次提交数据的机会。
除了鲨鱼控制器之外,Rails还为我们提供了一个index
视图模板,该视图对应于控制器中的index
方法。我们将使用这个视图作为应用程序的根视图,因此值得一看。
输入以下命令以输出该文件:
Output<p id="notice"><%= notice %></p>
<h1>Sharks</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Facts</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @sharks.each do |shark| %>
<tr>
<td><%= shark.name %></td>
<td><%= shark.facts %></td>
<td><%= link_to 'Show', shark %></td>
<td><%= link_to 'Edit', edit_shark_path(shark) %></td>
<td><%= link_to 'Destroy', shark, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Shark', new_shark_path %>
index
视图会遍历我们的Shark
类实例,这些实例已映射到数据库中的sharks
表。通过ERB模板,视图输出与每个鲨鱼实例关联的表中的各个字段:name
和facts
。
视图随后使用link_to
助手创建一个超链接,提供的字符串作为链接文本,提供的路径作为目标地址。这些路径的实现得益于我们在使用rails generate scaffold
命令定义sharks
资源路由时可用的助手。
除了查看index
视图,我们还可以查看new
视图,了解Rails如何在视图中使用局部模板。输入以下命令以输出app/views/sharks/new.html.erb
模板:
Output<h1>New Shark</h1>
<%= render 'form', shark: @shark %>
<%= link_to 'Back', sharks_path %>
尽管此模板看似缺少新建鲨鱼条目的输入字段,但提及的 `render 'form'
` 指示我们,模板正在引入 `_form.html.erb
` 局部视图,该局部视图提取了跨视图重复的代码片段。
查阅该文件将使我们全面了解如何创建新的鲨鱼实例:
Output<%= form_with(model: shark, local: true) do |form| %>
<% if shark.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(shark.errors.count, "error") %> prohibited this shark from being saved:</h2>
<ul>
<% shark.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :facts %>
<%= form.text_area :facts %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
此模板采用了 `form_with
` 表单辅助方法。表单辅助方法旨在利用特定模型的字段和作用域,简化从用户输入创建新对象的过程。在此,`form_with
` 以 `model: shark
` 为参数,其创建的新表单构建器对象包含与 `sharks
` 表字段相对应的输入字段。因此,用户拥有输入鲨鱼 `name
` 和鲨鱼 `facts
` 的表单字段。
提交此表单将生成包含用户数据的 JSON 响应,应用程序其余部分可通过 params 方法 访问这些数据,该方法会创建一个包含该数据的 `ActionController::Parameters
` 对象。
既然您已了解 `rails generate scaffold
` 为您生成的内容,接下来可以继续为应用程序设置根视图。
步骤 4 — 创建应用根视图并测试功能
理想情况下,您希望应用程序的着陆页映射到应用程序的根目录,以便用户能够立即了解应用程序的用途。
处理此问题有多种方法:例如,您可以创建一个 Welcome
控制器和一个相关的 index
视图,这将给用户一个通用的着陆页,同时还可以链接到应用程序的不同部分。然而,在本例中,让用户直接进入我们的 index
鲨鱼视图足以作为应用程序用途的介绍。
为了实现这一点,您需要在 config/routes.rb
中修改路由设置,以指定应用程序的根路径。
使用 nano
或您喜欢的编辑器打开 config/routes.rb
进行编辑:
文件内容如下:
Rails.application.routes.draw do
resources :sharks
# 有关此文件中可用的 DSL 的详细信息,请参阅 http://guides.rubyonrails.org/routing.html
end
如果没有设置更具体的内容,默认视图在 http://localhost:3000
或 http://your_server_ip:3000
将是默认的 Rails 欢迎页面。
为了将应用程序的根视图映射到鲨鱼控制器的`index`视图,您需要在文件中添加以下行:
Rails.application.routes.draw do
resources :sharks
root 'sharks#index'
# 有关此文件中可用的DSL的详细信息,请参阅http://guides.rubyonrails.org/routing.html
end
现在,当用户导航到您的应用程序根目录时,他们将看到一个完整的鲨鱼列表,并有机会创建新的鲨鱼条目,查看现有条目,以及编辑或删除特定条目。
完成编辑后,保存文件并退出编辑器。如果您使用`nano`编辑文件,可以通过按`CTRL+X`,`Y`,然后按`ENTER`来完成操作。
现在,您可以使用以下命令运行迁移:
您将看到确认迁移的输出。
再次启动您的Rails服务器。如果您在本地工作,请输入:
在开发服务器上,输入:
如果您在本地工作,请导航到`localhost:3000`,如果在开发服务器上工作,请导航到`http://your_server_ip:3000`。
您的应用程序登录页面将如下所示:
要创建新的鲨鱼,请点击页面底部的New Shark链接,这将带您到`sharks/new`路由:
让我们添加一些演示信息来测试我们的应用程序。在Name字段中输入“Great White”,在Facts字段中输入“Scary”:
点击Create按钮以创建鲨鱼。
这将引导你进入 show
路由,得益于 before_action
过滤器,它通过 set_shark
方法设置,该方法获取了我们刚刚创建的鲨鱼的 id
:
class SharksController < ApplicationController
before_action :set_shark, only: [:show, :edit, :update, :destroy]
. . .
def show
end
. . .
private
# 使用回调在动作间共享通用设置或约束。
def set_shark
@shark = Shark.find(params[:id])
end
. . .
你现在可以通过点击鲨鱼条目上的 编辑 来测试编辑功能。这将带你进入该鲨鱼的 edit
路由:
将大白鲨的 facts
从“可怕”改为“巨大”,然后点击 更新鲨鱼。这将带你回到 show
路由:
最后,点击 返回 将带你到更新后的 index
视图:
现在你已经测试了应用的基本功能,可以添加一些验证和安全检查,使一切更加安全。
步骤 5 — 添加验证
你的鲨鱼应用可以接受用户输入,但设想一个用户试图创建一个没有添加事实的鲨鱼,或者为数据库中已有的鲨鱼创建条目。你可以通过向模型添加验证来创建检查数据的机制,以确保数据在进入数据库之前是有效的。由于应用的逻辑位于其模型中,在这里进行数据输入验证比在应用的其他地方更有意义。
请注意,本教程不会涉及编写验证测试的内容,但您可以通过查阅Rails 文档来了解更多关于测试的信息。
如果您尚未停止服务器,请继续输入CTRL+C
来停止它。
打开您的shark.rb
模型文件:
当前,文件告诉我们Shark
类继承自ApplicationRecord
,而后者又继承自ActiveRecord::Base
:
class Shark < ApplicationRecord
end
首先,让我们为name
字段添加一些验证,确保该字段被填写且条目是唯一的,以防止重复条目:
class Shark < ApplicationRecord
validates :name, presence: true, uniqueness: true
end
接下来,为facts
字段添加验证,确保它也被填写:
class Shark < ApplicationRecord
validates :name, presence: true, uniqueness: true
validates :facts, presence: true
end
我们在这里不太关心事实的唯一性,只要它们与唯一的鲨鱼条目相关联即可。
完成后保存并关闭文件。
再次启动服务器,使用rails s
或rails s --binding=your_server_ip
,取决于您是在本地工作还是在开发服务器上。
导航到您应用程序的根路径,地址为http://localhost:3000
或http://your_server_ip:3000
。
点击新建鲨鱼。在表单中,将“大白鲨”添加到名称字段,将“大牙齿”添加到特点字段,然后点击创建鲨鱼。您应该会看到以下警告:
现在,让我们看看是否能检查其他验证。点击返回回到主页,然后再次点击新建鲨鱼。在新表单中,在名称字段输入“虎鲨”,并保持特点字段为空。点击创建鲨鱼将触发以下警告:
通过这些更改,您的应用程序已设置了一些验证,以确保保存到数据库的数据一致性。现在,您可以将注意力转向应用程序的用户,并定义谁可以修改应用程序数据。
第六步 — 添加认证
有了验证措施,我们对保存到数据库的数据有了一定的保障。但用户呢?如果我们不希望任何用户都能向数据库添加数据,那么我们应该添加一些认证措施,确保只有授权用户才能添加鲨鱼。为此,我们将使用http_basic_authenticate_with
方法,该方法允许我们创建用户名和密码组合来验证用户。
在 Rails 中,有多种方式可以对用户进行身份验证,包括使用 bcrypt
或 devise
等 gem。然而,目前我们将在应用控制器中添加一个方法,该方法将适用于整个应用程序的各个动作。如果将来我们为应用程序添加更多控制器,这将非常有用。
再次使用 CTRL+C
停止服务器。
打开定义 ApplicationController
的文件:
在其中,你会看到 ApplicationController
类的定义,应用程序中的其他控制器都继承自该类:
class ApplicationController < ActionController::Base
end
为了验证用户,我们将使用 http_basic_authenticate_with
方法,并硬编码用户名和密码。将以下代码添加到文件中:
class ApplicationController < ActionController::Base
http_basic_authenticate_with name: 'sammy', password: 'shark', except: [:index, :show]
end
除了在此处提供用户名和密码外,我们还通过指定不需要进行身份验证的路由(index
和 show
)来限制身份验证。另一种实现方式是写成 only: [:create, :update, :destroy]
。这样,所有用户都能查看所有的鲨鱼并阅读特定鲨鱼的事实。然而,在涉及到修改网站内容时,用户需要证明他们有权限。
在一个更健壮的设置中,您不会希望以这种方式硬编码值,但为了演示目的,这将使您了解如何为应用程序的路由包含身份验证。它还让您看到Rails默认情况下如何在cookies中存储会话数据:一旦您在指定的操作上进行身份验证,您在同一会话中将不再需要重新进行身份验证。
完成编辑后,保存并关闭app/controllers/application_controller.rb
。现在,您可以测试身份验证的实际效果了。
使用rails s
或rails s --binding=your_server_ip
启动服务器,并导航到您的应用程序,网址可以是http://localhost:3000
或http://your_server_ip:3000
。
在登录页面上,点击New Shark按钮。这将触发以下身份验证窗口:
如果您输入添加到app/controllers/application_controller.rb
中的用户名和密码组合,您将能够安全地创建一条新的鲨鱼记录。
现在,您拥有了一个功能齐全的鲨鱼应用程序,具备了数据验证和基本身份验证方案。
结论
您在本教程中创建的 Rails 应用程序是一个起点,您可以在此基础上进行进一步开发。如果您有兴趣探索 Rails 生态系统,项目文档是一个很好的起点。
您还可以通过阅读如何在 Ruby on Rails 应用程序中创建嵌套资源来了解更多关于向项目中添加嵌套资源的信息,这将指导您如何构建应用程序的模型和路由。
此外,您可能还想探索如何使用 React 等框架为您的项目设置更强大的前端。如何使用 React 前端设置 Ruby on Rails 项目提供了这方面的指导。
如果您想探索不同的数据库选项,还可以查看如何在Ubuntu 18.04上将PostgreSQL与您的Ruby on Rails应用程序一起使用,该指南详细介绍了如何使用PostgreSQL而不是SQLite进行工作。您还可以参考我们的PostgreSQL教程库,以了解更多关于使用此数据库的信息。
Source:
https://www.digitalocean.com/community/tutorials/how-to-build-a-ruby-on-rails-application