经典 MVC 架构
- 路由(router)根据请求路径来选择控制器(Controller)
- 控制器选择合适的视图(View),渲染给用户
- 如果涉及到数据库,控制器会调用 Modle 拿数据
- Modle 会调用 ORM 来简化数据操作
- ORM 会直接与数据库打交道
- Rails 的 ActiveRecord 是一个超级强大的 ORM
这么看起来,Rails 很简单?
- 上面的架构图隐藏了 Rails 的大部分功能
- 简单的东西往往更耐用(Rails 始于 2004 火于 2012)
- 但那时的中国开发者居然喜欢上了 PHP
- 目前大部分的开发者对 Rails 的印象就是慢,其实这么多年过去了他已经不慢了
Rails 的依赖 – Rack
功能
- 提供非常简单的 API
- 封装了 HTTP request 和 HTTP response
- 提出了中间件模型
一个简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| require 'rack' require 'webrick'
class RackApp def call(env) [ 200, {}, ['<h1>Rack</h1>'] ] end end
Rack::Handler::WEBrick.run RackApp.new, Host: '0.0.0.0', Port: '1234' // lambda require 'rack' require 'webrick' Rack::Handler::WEBrick.run ->(env) { [ 200, {"Content-Type" => "text/html;charset=utf-8"}, ["<h1>rack_lambda</h1>", "<p>第二行内容</p>"] ] }, Host: '0.0.0.0', Port: 1234
|
请求
用法,env
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| require 'rack' require 'webrick'
class RackApp def call(env) request = Rack::Request.new(env) p "你请求的路径是:#{request.path}" [ 200, {}, ['<h1>Rack</h1>'] ] end end
Rack::Handler::WEBrick.run RackApp.new, Host: '0.0.0.0', Port: '1234' s
|
中间件模型
用户请求之后,服务器响应之前,放在
- Rack 模仿管道 pipe 实现了自己的中间件模型
- 也就是把 req 和 res 依次传给不同类,得到最终结果
- 举例CommonLogger
1 2 3 4 5 6 7 8 9
| require 'rack' require 'webrick' app = Rack::Builder.app do use Rack::CommonLogger run -> (env){ [200, {}, ['<h1>CommonLogger</h1>']] } end Rack::Handler::WEBrick.run app, Host: '0.0.0.0', Port: 1234, AccessLog: []
|
先用 AccessLog: [] 禁用默认的 log
再使用 use Rack::CommonLogger 来引入中间件
对比其他
发现 Rack 和 Express 很像
- 查阅发现,Express 一开始就是受 Rack 启发而写的
- Issue
Rack 和 Rails 的区别
- Rack 只是对请求和响应进行了简单封装
- 由于它很简单易学,所以他被各种框架和中间件采用了
- Rails 包涵了你需要的一切功能,也包含了 Rack
创建 Rails 项目
首先为了防止 gem install 很慢
- gem install 后面添加 –verbose
- 编辑 ~/.gemrc ,最后一行写入
gem: "--no-document"
,因为默认 gem 在下载包的时候会下载文档,而一般这个文档没什么用
- 按 Ruby China说的做
gem 是什么
- 类似于 Node.js 里面的 npm
- gem install 用于全局安装依赖
- 局部安装依赖可以用 bundle install
步骤
- gem install rails –version=6.0.2.2
- rails –help 看看选项
rails new morney-rails1 --database=postgresql --skip-action-mailbox --skip-action-text --skip-sprockets --skip-javascript --skip-turbolinks --skip-system-test --skip-test --api --skip-webpack-insall
(postgresql 数据库,不要收件箱,不要富文本,不要 sprockets,不要 js,不要turbolinks,不要系统测试,不要测试,使用api模式,api模式是一个比较轻量的模式,不要 webpack)
- 在 .gitignore 里添加 .idea
Hello Rails
在 routes.rb 里写
1 2 3
| Rails.application.routes.draw do get '/hello', to: 'first end
|
创建 app/controllers/first_controller.rb
1 2 3 4 5
| class FirstController < ApplicationController def hello render plain: 'hello' end end
|
运行命令 bin/rails serve
(可缩写为s)
发现数据库报错,因为默认 rails 是有数据库的,但是却发现连接不上
安装数据库
1
| docker run -v morney-rails1-data:/var/lib/postgresql/data -p 5001:5432 -e POSTGRES_USER=morney -e POSTGRES_PASSWORD=123456 -d postgres:12.2
|
配置数据库:config/database.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| default: &default adapter: postgresql encoding: unicode pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: morney password: 123456 host: localhost // 或者 192.168.99.100 你的 docker ip port: 5001
development: <<: *default database: morney_rails1_development test: <<: *default database: morney_rails1_test production: <<: *default database: morney_rails1_production username: morney_rails1 password: <%= ENV['MORNEY_RAILS_1_DATABASE_PASSWORD'] %>
|
注意账户密码是安装psql时帐号密码,
注意生产环境的密码不能直接写在配置文件中,一般以环境变量的形式
创建数据库
让 rails 根据配置文件自动创建数据库
配置修改文件自动重启
只有 windows 用户才存在这个问题(新版好像也不会出现这个问题了)
- 打开 config/environments/development.rb
- 将文件末尾的 config.file_watcher 接触注释
- 然后在 Gemfile 加上这两句话
1 2 3 4
| group :development do gem 'listen' gem 'wdm', '>= 0.1.0', platforms: [:mingw, :mswin, :x64_mingw, :jruby] end
|
- 安装依赖
bin/bundle install
渲染 JSON
1 2 3 4 5
| class FirstController < ApplicationController def hello render json: {name: 'zch', age: 18} end end
|
渲染 HTML
如果前后端彻底分离
- 那么 Rails 服务器一般是不负责 HTML 的
- 我们会让 nginx 来负责 HTML
如果分离不彻底呢?
- Rails 也是可以用来渲染 HTML 的
- 在 application_controller 里加上
include ActionView::Layouts
- Rails 就会按照上约定寻找对应的 HTML 模版
- 如果需要在 HTML 中插入 ruby,就以 .erb 结尾
<% ___ %>
用于写语句(一般没有值),如:if/else1 2 3 4 5 6 7
| <h1>我是一个页面</h1> <% a = 3 %> <% if a > 5%> a 很大 <% else %> a 很小 <% end %>
|
<%= __ %>
用于写表达式(一定有值),如: @xxx1 2 3
| <h1>我是一个页面</h1> <% a = 3 %> <%= a * 2 %>
|
1 2 3 4 5 6 7 8 9 10
| class FirstController < ApplicationController def hello @xxx = 'Controller 里面的 xxx 变量' render 'first/hello' end end
<h1>我是一个页面</h1>
<%= @xxx %>
|
- 如果让 Nginx 负责 HTML,就不用使用这些标签了
如何使用 layout
代码复用
- 默认的 layout 是 application.html.erb
- 可以使用 <%= yield %> 作为插槽
- 可以使用 <%= yield :footer %> 作为具名插槽
1 2 3 4 5 6 7 8
| <body> <%= yield %> <% if content_for?(:footer) %> <footer style="background-color: #c03"> <%= yield :footer %> </footer> <% end %> </body>
|