大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
Gems 与框架
这一课你将能做到
- 用 RubyGems 安装、管理第三方库,理解 gem 的版本约束语法
- 用 Bundler 管理项目依赖,写 Gemfile 和 Gemfile.lock
- 理解 Rack 的中间件机制,并用 Sinatra 写一个最小 Web 应用
为什么要学
Ruby 的强大不在语言本身,而在生态——Rails 只是冰山一角,背后是 18 万个 gem。Bundler 是 Ruby 依赖管理的标准答案,Rack 是 Ruby Web 的 HTTP 抽象层,Sinatra 是「100 行写个 API」的极简框架。不懂这些,等于进了 Ruby 世界却只会用裸 Ruby。
人话:gem 是「别人写好的工具包」,Bundler 是「项目工具箱管理员」,Rack 是「Web 服务器和框架之间的翻译官」,Sinatra 是「极简 Web 框架」。四者配合,Ruby 才能从脚本语言变成生产级 Web 平台。
先建立图像
Ruby Web 栈分层
┌─────────────────────────────────────┐
│ 你的应用代码(Sinatra / Rails) │
├─────────────────────────────────────┤
│ Rack(中间件接口:call(env)) │
├─────────────────────────────────────┤
│ Web 服务器(Puma / Unicorn / Thin) │
├─────────────────────────────────────┤
│ Ruby 解释器 + Gems │
└─────────────────────────────────────┘
Bundler 依赖解析:
Gemfile(声明)──▶ Bundler 解析 ──▶ Gemfile.lock(锁定)
│ │
▼ ▼
"~> 7.0" rails (7.0.4.3)
">= 1.0, < 2.0" exact version
跟着做
步骤 1:RubyGems 基础
# 安装 gem
gem install rails # 安装最新版
gem install rails -v 7.0.4 # 指定版本
gem install rails --pre # 预发布版
# 查看已安装
gem list # 本地已安装
gem list rails # 查看特定 gem
gem outdated # 查看可更新的
# 搜索与信息
gem search sinatra # 远程搜索
gem info rails # 查看详细信息
# 卸载与清理
gem uninstall rails
gem cleanup # 清理旧版本
步骤 2:Bundler 项目依赖
新建项目目录,创建 Gemfile:
# Gemfile
source "https://rubygems.org"
ruby "3.3.5"
# 生产依赖
gem "sinatra", "~> 4.0"
gem "puma", "~> 6.0"
gem "redis", "~> 5.0"
# 开发/测试组
group :development, :test do
gem "rspec", "~> 3.12"
gem "pry" # 调试神器
gem "rubocop", require: false
end
# 仅开发组
group :development do
gem "rerun" # 代码变更自动重启
end
# 安装依赖(生成 Gemfile.lock)
bundle install
# 更新特定 gem
bundle update sinatra
# 查看依赖树
bundle viz # 需要 graphviz
# 在 bundle 环境执行命令(确保用 lock 里的版本)
bundle exec ruby app.rb
bundle exec rspec
Gemfile.lock 示例片段:
GEM
remote: https://rubygems.org/
specs:
sinatra (4.0.0)
mustermann (~> 3.0)
rack (~> 3.0)
...
步骤 3:Rack——Web 的通用接口
# 最小 Rack 应用:任何响应 call(env) 的对象都是 Rack 应用
class HelloRack
def call(env)
# env 是包含请求信息的 Hash
path = env["PATH_INFO"]
method = env["REQUEST_METHOD"]
body = case path
when "/" then "首页"
when "/about" then "关于我们"
else "404"
end
# 返回 [状态码, 响应头, 响应体(可迭代)]
[200, { "Content-Type" => "text/plain; charset=utf-8" }, [body]]
end
end
# 用 Rack 内置服务器运行(ruby hello_rack.rb 后访问 localhost:9292)
require "rack"
Rack::Handler::WEBrick.run(HelloRack.new, Port: 9292)
Rack 中间件——洋葱模型:
# 中间件:包装应用的「层」
class TimerMiddleware
def initialize(app)
@app = app
end
def call(env)
start = Time.now
status, headers, body = @app.call(env) # 调用下一层
elapsed = Time.now - start
headers["X-Response-Time"] = "#{elapsed}s"
[status, headers, body]
end
end
# 使用
app = TimerMiddleware.new(HelloRack.new)
Rack::Handler::WEBrick.run(app, Port: 9292)
步骤 4:Sinatra——极简 Web 框架
# gem install sinatra puma
# app.rb
require "sinatra"
# 路由:HTTP 方法 + 路径
get "/" do
"Hello, Sinatra!"
end
get "/users/:id" do
"用户 ID: #{params[:id]}"
end
post "/users" do
content_type :json
{ name: params[:name], created: true }.to_json
end
# 过滤器:before/after
before do
@start_time = Time.now
end
after do
puts "请求耗时: #{Time.now - @start_time}s"
end
# 错误处理
not_found do
"页面不存在"
end
error do
"服务器错误: #{env['sinatra.error']}"
end
# 运行:ruby app.rb,访问 localhost:4567
步骤 5:Rails 生态速览
# 创建 Rails 应用(需要先 gem install rails)
rails new myapp --database=postgresql
cd myapp
rails server # 启动开发服务器
# 常用生成器
rails generate model User name:string email:string
rails generate controller Users index show
rails generate migration AddAgeToUsers age:integer
# 数据库
rails db:create
rails db:migrate
rails console # 进入 Rails console(类似 irb 但加载了应用)
Rails 核心概念速查:
| 概念 | 作用 | 文件位置 |
|---|---|---|
| Model | 数据层(ActiveRecord) | app/models/ |
| View | 展示层(ERB 模板) | app/views/ |
| Controller | 控制层 | app/controllers/ |
| Route | 路由 | config/routes.rb |
| Migration | 数据库迁移 | db/migrate/ |
| Concern | 模块复用 | app/models/concerns/ |
讲清楚要点
- Gemfile 的版本约束:
~> 7.0表示>= 7.0 且 < 8.0;~> 7.0.4表示>= 7.0.4 且 < 7.1。>= 1.0, < 2.0是区间。锁定版本用Gemfile.lock,团队协作必须提交。 - Rack 的
call(env)协议:任何 Ruby 对象只要实现call(env)返回[status, headers, body],就是 Rack 应用。Rails、Sinatra、Hanami 都基于 Rack,中间件可以跨框架复用。 - Sinatra 的 block 是路由处理器:
get "/path" do ... end的 block 在请求匹配时执行,params自动解析查询字符串和路径参数。返回值自动作为响应体。 - Bundler 的
bundle exec是必须的:不加bundle exec,系统可能加载了其他版本的 gem,导致「在我机器上是好的」。CI/CD 脚本里所有 Ruby 命令都要加bundle exec。 - Rails 是「约定优于配置」:表名自动复数化、文件路径自动映射、关联自动推断。理解约定比写配置更重要。
你可能会懵的地方
-
Gemfile 和 Gemfile.lock 的关系? Gemfile 是「意图声明」(我要什么范围),Gemfile.lock 是「精确快照」(实际装了什么版本)。团队开发必须提交 lock,保证所有人环境一致。
-
bundle install和bundle update的区别?install按 lock 文件安装(如果没 lock 就解析 Gemfile 生成);update忽略 lock 重新解析最新兼容版本。日常用install,升级用update gem_name。 -
Rack 中间件和执行顺序? 中间件是「包装纸」,一层包一层。请求进来时从最外层剥到最内层,响应出去时从最内层穿到最外层。顺序就是
use的声明顺序。 -
Sinatra 和 Rails 怎么选? Sinatra:微服务、API 网关、原型验证、嵌入式设备。Rails:全功能 Web 应用、快速 MVP、需要 ORM/后台任务/邮件等完整生态。Sinatra 是「瑞士军刀」,Rails 是「工具箱」。
-
require和require_relative的区别?require从$LOAD_PATH查找(包括 gem);require_relative从当前文件相对路径查找。项目内部文件用require_relative,外部 gem 用require。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 不提交 Gemfile.lock | 团队环境不一致 | lock 文件必须进版本控制 |
gem install 代替 bundle install | 项目依赖没锁定 | 项目内一律 bundle install |
Sinatra 路由写 get "/users?id=1" | 查询参数不在路径里 | get "/users" 用 params[:id] |
| Rack 应用返回字符串而不是数组 | Rack 协议要求 [status, headers, body] | 严格返回三元组 |
| Rails 里手写 SQL 字符串拼接 | SQL 注入风险 | 用 where("name = ?", params[:name]) |
卡点急救
bundle install卡在某个 gem 编译失败:该 gem 有 C 扩展。安装系统依赖:brew install openssl(macOS)或apt install build-essential libssl-dev(Ubuntu)。- Sinatra 改了代码不生效:Sinatra 默认不自动重载。开发环境装
rerungem:rerun 'ruby app.rb'。 - Rails 报
LoadError: cannot load such file:文件路径或类名不匹配约定。Rails 的 autoload 要求app/models/user.rb里必须是class User。
面试常问
-
Rack 是什么?为什么重要? Rack 是 Ruby Web 服务器和框架之间的最小接口(
call(env)返回[status, headers, body])。它让任何 Ruby Web 框架可以跑在任何 Ruby Web 服务器上,中间件可以跨框架复用。Rails、Sinatra、Hanami 都基于 Rack。 -
Bundler 的依赖解析算法? Bundler 用「解析树 + 回退」算法:从 Gemfile 的约束出发,递归解析每个 gem 的依赖,找满足所有约束的版本组合。冲突时回退尝试其他版本。比 npm 的嵌套 node_modules 更严格,保证全局唯一版本。
-
Sinatra 和 Rails 的核心差异? Sinatra 是 DSL 风格的路由框架,代码即配置;Rails 是 MVC 全栈框架,约定优于配置。Sinatra 适合小而美的 API,Rails 适合大而全的 Web 应用。
自测三问
Gemfile和Gemfile.lock分别解决什么问题?为什么都要提交?- Rack 应用的三个返回值分别是什么?中间件如何包装应用?
bundle exec的作用是什么?不加会有什么风险?
小结一句话
RubyGems 是工具箱,Bundler 是管理员,Rack 是翻译官,Sinatra 是瑞士军刀,Rails 是航空母舰——生态选对了,开发效率翻倍。
延伸
- Bundler 官方文档
- Rack 官方规范
- 下一课:测试与质量——RSpec、RuboCop 与调试技巧。