ruby china wiki:https://ruby-china.org/wiki
The Rails Doctrine: https://ruby-china.org/wiki/the-rails-doctrine
Guides:
ruby toolbox: https://www.ruby-toolbox.com/
最近国内互联网就业市场持续低迷,作为主要着力于前端技术的我,也开始探索后端、部署相关的技术。之前除了接触过 Node.js,还有一门我一直想学习和应用的语言就是 Ruby 了。
第一次听说 Ruby 是在 2020 年的夏天,当时还是土木 的我,从前辈口中听说了 Ruby 这个词,他说他要亲自教我,但是没有天赋的我还是去土木和设计行业卷了一阵子才正式返航计算机。虽迟但到,在 2023 年的夏天,我写下这一篇快速入门,也算是一种重逢吧!
Ruby 同样是一门面向对象的语言,抛开性能不谈,它的语法非常简单,行文甚至比 Python 还要简洁,而且足够语义化,这也是我选择它的重要原因。Rails 作为 Ruby 的开发框架,和大部分其他语言框架一样采用 MVC 架构(附录 A 中我添加了 MVC 的说明),它提供了一些工具和函数来快速开发 Web 应用程序。另一方面,它还支持主流的数据库,比如:MySQL、PostgreSQL 和 SQLite 等。
目前,我正在开发一个 H5 小应用,数据库使用的是 PostgreSQL,总体体验下来,还算 OK,如果要问我,什么是 Rails?
Rails = Routes + MVC
以下是正文。
安装 ruby 的过程我就省略了,安装完成后执行 ruby --version
来查看版本。
在 docker 容器中执行以下命令生成一个 rails api 服务
shell gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/ bundle config mirror.https://rubygems.org https://gems.ruby-china.com gem install rails -v 7.0.2.3 pacman -S postgresql-libs cd ~/repos rails new --api --database=postgresql --skip-test catdou-1 code catdou-1 bin/rails server
会报错,需要启动一个数据库,如下。
在宿主机终端执行以下命令启动一个 postgres 数据库(版本为 14)
shell docker run -d --name db-for-catdou -e POSTGRES_USER=catdou -e POSTGRES_PASSWORD=123456 -e POSTGRES_DB=catdou_dev -e PGDATA=/var/lib/postgresql/data/pgdata -v catdou-data:/var/lib/postgresql/data --network=network1 postgres:14
配置开发环境变量,config/database.yml
yaml development: <<: *default database: catdou_dev username: catdou password: 123456 host: db-for-catdou
重新运行 server
shell bin/rails server
user 是表名,email 和 name 是字段
shell bin/rails g model user email:string name:string
生成数据库 migrate 文件以及 model 文件:
db/migrate/20230607152514createusers.rb
ruby class CreateUsers < ActiveRecord::Migration[7.0] # 定义一个类,用于创建表 def change create_table :users do |t| # 方法名为 create_table,表名为 users t.string :email # 创建字段 email,类型为 string t.string :name # 创建字段 name,类型为 string t.timestamps # 创建时间字段:updated_at 更新时间,created_at 创建时间 end end end
app/models/user.rb
ruby class User < ApplicationRecord end
将创建的 user 模型迁移到 postgres 数据库(会生成一个 users 表)
shell bin/rails db:migrate bin/rails db:rollback step=1 # 如果需要的话,可以用它将数据库回退到上一步
生成 users 的 controller,包括 show 和 create 方法
shell bin/rails g controller users show create
生成 users 的控制器文件以及添加相应路由
app/controllers/users_controller.rb(源文件已做修改)
```ruby class UsersController < ApplicationController def show user = User.findbyid params[:id] # 在 users 表中找到对应 id 的那一行记录 if user render json: user # 如果存在,返回 user else head 404 # 如果不存在,返回一个 404 响应码 end end
def create # 在 users 表中新建一条记录,email 是 '[email protected]',name 是 'eric' user = User.new email: '[email protected]', name: 'eric' if user.save # 如果保存成功了 render json: user # 返回给前端 json 数据(新建的 user) else # 否则 render json: user.errors # 返回给前端 json 数据(user 的报错) end end ```
config/routes.rb(路由文件中会自动添加以下两行内容)
ruby get 'users/show' get 'users/create'
路由文件需要修改,上面自动生成的两句删除不用,添加以下两句代码到 routes.rb 中:
ruby get "/users/:id", to: "users#show" # 当用户对 "/users/:id" 发起 get 请求时,对应 controller 动作为 show post "/users/", to: "users#create" # 当用户对 "/users/" 发起 post 请求时,对应 controller 动作为 create
数据校验一般在 model 层进行。假设,需要对 users 表的 email 字段进行必填校验。
那么在 app/models/users.rb
中添加以下代码即可:
ruby class User < ApplicationRecord validates :email, presence: true # email 是必填的 end
https://restfulapi.cn/
https://medium.com/@haldar.mahesh/restful-api-designing-guidelines-the-best-practices-60e1d954e7c9
| HTTP Method | API Path | Description | | ----------- | --------------------------- | -------------- | | GET | api/v1/zoos | 列出所有动物园 | | POST | api/v1/zoos | 新建一个动物园 | | GET | api/v1/zoos/:id | 获取某个指定动物园的信息 | | PUT | api/v1/zoos/:id | 更新某个指定动物园的全部信息 | | PATCH | api/v1/zoos/:id | 更新某个指定动物园的部分信息 | | DELETE | api/v1/zoos/:id | 删除某个动物园 | | GET | api/v1/zoos/:id/animals | 列出某个指定动物园的所有动物 | | DELETE | api/v1/zoos/:id/animals/:id | 删除某个指定动物园的指定动物 |
根据产品需求和 UI、UX 设计数据库与 API。
利用 namespace 构建以以 /api/v1
开头的 api 路由表:
config/routes.rb
ruby Rails.application.routes.draw do namespace :api do namespace :v1 do # /api/v1 resources :validation_codes, only: [:create] resource :session, only: [:create, :destroy] resource :me, only: [:show] resources :items resources :tags # resources :taggings, only: [:create, :index, :destroy] end end end
生成路由表:bin/rails routes
```shell $ bin/rails routes Prefix Verb URI Pattern Controller#Action
apiv1validationcodes POST /api/v1/validationcodes(.:format) api/v1/validation_codes#create
api_v1_session DELETE /api/v1/session(.:format) api/v1/sessions#destroy
POST /api/v1/session(.:format) api/v1/sessions#create
api_v1_me GET /api/v1/me(.:format) api/v1/mes#show
api_v1_items GET /api/v1/items(.:format) api/v1/items#index
POST /api/v1/items(.:format) api/v1/items#create
api_v1_item GET /api/v1/items/:id(.:format) api/v1/items#show
PATCH /api/v1/items/:id(.:format) api/v1/items#update
PUT /api/v1/items/:id(.:format) api/v1/items#update
DELETE /api/v1/items/:id(.:format) api/v1/items#destroy
api_v1_tags GET /api/v1/tags(.:format) api/v1/tags#index
POST /api/v1/tags(.:format) api/v1/tags#create
api_v1_tag GET /api/v1/tags/:id(.:format) api/v1/tags#show
PATCH /api/v1/tags/:id(.:format) api/v1/tags#update
PUT /api/v1/tags/:id(.:format) api/v1/tags#update
DELETE /api/v1/tags/:id(.:format) api/v1/tags#destroy
```
按照附录 A 依次创建 model、迁移数据库,创建 controller
rspec # BDD for Rails(行为驱动开发)
目的:对 model、controller 进行测试
前提:需要一个测试环境的数据库
现在已经有开发环境的数据库(catdou_dev)了,现在以这个数据库为例,做数据表的迁移。
在迁移之前,需要配置并新建一个测试环境的数据库(catdou_test)。
环境参数配置
config/database.yml
```yaml
test: <<: *default database: catdou_test username: catdou password: 123456 host: db-for-catdou
```
新建数据库
shell bin/rails db:create RAILS_ENV=test
shell bin/rails db:migrate RAILS_ENV=test
如果缺少 model,执行 rails 提供的 model 生成命令即可。
Add rspec-rails
to both the :development
and :test
groups of your app’s Gemfile
:
```
group :development, :test do gem 'rspec-rails', '~> 6.0.0' end ```
Then, in your project directory:
```shell
$ bundle install
$ rails generate rspec:install create .rspec create spec create spec/spechelper.rb create spec/railshelper.rb ```
Creating boilerplate specs with rails generate: (如果 user 模型已经存在就不用重复生成了!直接运行第二个指令。)
```shell
$ rails generate model user invoke activerecord create db/migrate/20181017040312createusers.rb create app/models/user.rb invoke rspec create spec/models/userspec.rb
$ rails generate rspec:model user create spec/models/user_spec.rb
$ rails generate --help | grep rspec ```
Running specs:
```shell
$ bundle exec rspec
$ bundle exec rspec spec/models
$ bundle exec rspec spec/controllers/accountscontrollerspec.rb
$ bundle exec rspec spec/controllers/accountscontrollerspec.rb:8
$ bundle exec rspec --help ```
:测试 user 模型:rails generate rspec:model user
之后会创建出一个 spec/models/user_spec.rb 文件(已改源码):
```ruby require "rails_helper"
RSpec.describe User, type: :model do it '有 email' do user = User.new email: '[email protected]' # 新建一个实例,有一个 email 为 '[email protected]' expect(user.email).to eq('[email protected]') # 期望A等于B end end ```
运行测试用例:bundle exec rspec
shell $ bundle exec rspec . Finished in 0.11852 seconds (files took 4.61 seconds to load) 1 example, 0 failures
一个点代表一个测试用例成功执行。
:测试 validation_codes controller:bin/rails g rspec:request validation_codes
app/controllers/api/v1/validationcodescontroller.rb
ruby class Api::V1::ValidationCodesController < ApplicationController def create code = SecureRandom.random_number.to_s[2..7] # 随机数取6位 validation_code = ValidationCode.new email: params[:email], kind: "sign_in", code: code if validation_code.save head 201 else render json: { errors: validation_code.errors } end end end
spec/requests/validationcodesspec.rb
```ruby require "rails_helper"
RSpec.describe "ValidationCodes", type: :request do describe "POST validationcodes#create" do it "can be created" do post "/api/v1/validationcodes", params: { email: "[email protected]" } expect(response).to havehttpstatus(201) end end end ```
+----------------------+ | User's Request | +----------------------+ | v +----------------------+ | Controller Layer | +----------------------+ | v +----------------------+ | Model Layer | +----------------------+ | v +-----------------------+ | Database or Service | +-----------------------+ | v +-----------------------+ | Response to User | +-----------------------+
用户发送请求后,请求会进入 Controller 层。Controller 层负责接收和解析请求,处理业务逻辑,然后将数据传递给 Model 层进行处理。Model 层负责数据的读取、修改、删除等操作,并将处理后的结果保存到数据库或者其他服务中。最终,Controller 层将经过处理的数据返回给用户。整个过程中,View 层负责将数据渲染成最终的呈现形式(如 HTML 页面、JSON 响应等),但这并不是 MVC 模式的必要组成部分,因为 Ruby on Rails 中有一个概念叫做 Action View,它将 View 层的功能集成在了 Controller 层中,使得开发更加高效简洁。【以上绘图和回答来自 ChatGPT】
view 层,用于数据渲染和视图展示,用户访问路径时会向后端发送请求。
controller 层,负责响应用户的请求(HTTP:GET、POST、PUT/PATCH、DELETE),这些请求通过路由映射到 controller 中,执行 CRUD 相关操作。
model 层,用于数据处理和存储。比如:数据的验证、转换、过滤、存储。
shell curl http://127.0.0.1:3000/api/users/1 curl http://127.0.0.1:3000/api/users/1 -v # -v 表示 verbose 详细模式,请求头、响应头之类的会被打印出来
shell curl -X POST http://127.0.0.1:3000/api/users
postgresql explorer: postgresql
前提:构建了 Rails 服务(并连接了数据库):rails new --api --database=postgresql --skip-test catdou-1
第一步、routes,生成路由表: bin/rails routes
:利用 namespace 生成一个以 /api/v1
开头的 api 路由表:(对应 controller 文件要放在 controllers/api/v1 目录下)
config/routes.rb
ruby Rails.application.routes.draw do namespace :api do namespace :v1 do # /api/v1 resources :validation_codes, only: [:create] resource :session, only: [:create, :destroy] resource :me, only: [:show] resources :items resources :tags end end end
第二步、model,生成(User)模型并在数据库中生成(users)表:bin/rails g model user email:string name:string
Tip:模型是单数,如:User,对应的数据库表名是复数,如:users
为什么model 类是单数,而迁移文件的表会自动对应到复数?https://ruby-china.org/wiki/the-rails-doctrine
和 Matz 一样,我有时候为了实现我的理念也会做出一些蠢事。一个例子便是 Inflector,一个可以对英文做不规则转化的类,譬如 Person 类对应到 People 表、Analysis 对应到 Analyses,Comment 对应到 Comments 等。这个东西现在已经是 Rails 不可分割的元素了,但早期争议的怒火延烧到今日,伤口仍未愈合,由此可见其重要性。
以及指导手册上的 :
BookClub
).book_clubs
).| Model / Class | Table / Schema | | ------------- | -------------- | | Article
| articles
| | LineItem
| line_items
| | Deer
| deers
| | Mouse
| mice
| | Person
| people
|
第三步、migrate,迁移文件,创建数据库表(users):bin/rails db:migrate
bin/rails db:migrate RAILS_ENV=development
bin/rails db:rollback
bin/rails db:drop
第四步、controller,生成控制器(要写复数):bin/rails g controller Api::V1::Users show
:因为第一步的路由文件设置了 namespace,所以 controller 文件中第一行的 Class 类要以 Api::V1:: 开头!
ruby class Api::V1::UsersController < ApplicationController end
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
| HTTP 状态码 | 含义 | 备注 | | -------- | ------------------------------- | ------------- | | 200 | OK 成功 | | | 201 | Created 创建成功 | 资源创建成功 | | 404 | Not Found 未找到 | | | 403 | Forbidden 拒绝授权 | | | 401 | Unauthorized 未登录 | 缺少身份验证凭证 | | 422 | Unprocessable Entity 无法处理,参数有问题 | | | 402 | Payment Required 需付费 | | | 412 | Precondition Failed 不满足前提条件 | | | 429 | Too Many Requests 请求太频繁 | 频次限制 | | 400 | Bad Request 其他错误请求 | 错误详情放在 body 里 |
string
:字符串类型,用于表示文本数据。text
:字符串类型,用于表示大文本数据。integer
:整数类型,用于表示整数数据。float
:浮点数类型,用于表示浮点数数据。decimal
:高精度小数类型,用于表示精度比较高的小数数据。datetime
:日期和时间类型,用于表示日期和时间数据。timestamp
:时间戳类型,用于记录数据的创建和更新时间。time
:时间类型,用于表示时间数据。date
:日期类型,用于表示日期数据。binary
:二进制类型,用于存储二进制数据,如图片等。boolean
:布尔类型,用于表示真假数据。Ruby 是“红宝石”的意思,而 Gem 是“宝石”的意思。
Gem 相当于 NPM,都是包管理器。
Gemfile, Gemfile.lock 相当于 Node 项目中的 package.json, package-lock.json,描述了项目需要的依赖关系。
但一般使用 bundle 来安装项目所需的所有 gem 包:bundle install
或 bundle
(查看安装详情:bundle --verbose
)
换国内的源,加速下载:打开 Gemfile,找到第一行,将默认的 source "https://rubygems.org"
换成 source "https://gems.ruby-china.com/"
注意:每次安装完成后,因为依赖变了,和前端一样,需要重启一下服务!
gem 常用指令:
gem install
:安装指定的 gem 包。gem uninstall
:删除指定的 gem 包。gem update
:更新指定的 gem 包。gem list
:列出所有已安装的 gem 包。gem search
:搜索包含关键词的 gem 包。gem env
:显示当前 gem 环境的配置信息。gem sources
:列出所有可用的 gem 源。gem sources --add
:添加一个新的 gem 源。gem help
:查看 gem 命令的帮助信息。bundle 常用指令:
bundle install
:根据 Gemfile.lock 文件中的依赖关系,安装所有需要的 gem 包。如果 Gemfile.lock 文件不存在,它会先生成这个文件,然后再进行安装。当然,如果我们在 Gemfile 中添加了新的依赖项,执行 bundle install
还会安装这些新的依赖项。
bundle update
:检查 Gemfile 中的所有 gem 包的最新版本,并更新 Gemfile.lock 文件,同时安装更新后的 gem 包。
bundle exec
:运行特定版本的 gem 包。如果你在多个项目间使用了不同版本的 gem 包,可以使用这个命令来使用指定项目的 gem 包。这个命令用法如下:
bundle exec
其中
指运行的命令,例如 rails server
等。
bundle package
:将项目所需的 gem 包打成 gem 包并放到 vendor/cache 目录下,方便离线安装。
zsh 是一种 Unix shell,是 Bourne shell(sh)的扩展,也是 Bash、Ksh 等 shell 的改进版。它提供了更多的功能和自定义选项,如支持自动补全、历史命令搜索、别名等。
cd:切换当前工作目录
shell cd ~ # 回到家目录 cd .. # 回到上层 cd - # 回到上一次
ls:列出当前目录的文件和子目录
pwd:显示当前所在的工作目录的完整路径
alias:创建别名
unalias:删除别名
source:重新执行当前shell环境
emacs:进入emacs编辑器模式
vi:进入vi编辑器模式
history:查看历史命令
echo:输出文本信息
grep:查找文件中的文本内容
chmod:修改文件或目录的权限
chown:修改文件或目录的所有者
rm:删除文件或目录
cp:复制文件或目录
mv:移动文件或目录
mkdir:创建新目录
rmdir:删除空目录
cat:查看文件内容
touch:创建新空文件或更改文件的时间戳。
以上,如有谬误,还请斧正,希望这篇文章对你有所帮助,感谢您的阅读~
对了,如果你还没有我的好友,加我微信:enjoyMrcat,备注 「掘金」
,即有机会加入高质量前端交流群,在这里你将会认识更多的朋友;也欢迎关注我的公众号 见嘉 Being Dev
,并设置星标,以便第一时间收到更新。