CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Ruby 语言入门/课时/Gems 与框架
RawBlame
课时目录12 节

Ruby 语言入门

  1. 01Ruby 环境
  2. 02数据类型
  3. 03语法基础
  4. 04控制流
  5. 05方法与 Blocks
  6. 06OOP 与 Mixin
  7. 07元编程
  8. 08IO 与 Enumerable
  9. 09并发
  10. 10Gems 与框架
  11. 11测试与质量
  12. 12综合练习

Gems 与框架

Bundler/Rack/Rails。

30 分钟

Gems 与框架

这一课你将能做到

  1. 用 RubyGems 安装、管理第三方库,理解 gem 的版本约束语法
  2. 用 Bundler 管理项目依赖,写 Gemfile 和 Gemfile.lock
  3. 理解 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/

讲清楚要点

  1. Gemfile 的版本约束:~> 7.0 表示 >= 7.0 且 < 8.0;~> 7.0.4 表示 >= 7.0.4 且 < 7.1。>= 1.0, < 2.0 是区间。锁定版本用 Gemfile.lock,团队协作必须提交。
  2. Rack 的 call(env) 协议:任何 Ruby 对象只要实现 call(env) 返回 [status, headers, body],就是 Rack 应用。Rails、Sinatra、Hanami 都基于 Rack,中间件可以跨框架复用。
  3. Sinatra 的 block 是路由处理器:get "/path" do ... end 的 block 在请求匹配时执行,params 自动解析查询字符串和路径参数。返回值自动作为响应体。
  4. Bundler 的 bundle exec 是必须的:不加 bundle exec,系统可能加载了其他版本的 gem,导致「在我机器上是好的」。CI/CD 脚本里所有 Ruby 命令都要加 bundle exec。
  5. 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])

卡点急救

  1. bundle install 卡在某个 gem 编译失败:该 gem 有 C 扩展。安装系统依赖:brew install openssl(macOS)或 apt install build-essential libssl-dev(Ubuntu)。
  2. Sinatra 改了代码不生效:Sinatra 默认不自动重载。开发环境装 rerun gem:rerun 'ruby app.rb'。
  3. 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 应用。

自测三问

  1. Gemfile 和 Gemfile.lock 分别解决什么问题?为什么都要提交?
  2. Rack 应用的三个返回值分别是什么?中间件如何包装应用?
  3. bundle exec 的作用是什么?不加会有什么风险?

小结一句话

RubyGems 是工具箱,Bundler 是管理员,Rack 是翻译官,Sinatra 是瑞士军刀,Rails 是航空母舰——生态选对了,开发效率翻倍。

延伸

  • Bundler 官方文档
  • Rack 官方规范
  • 下一课:测试与质量——RSpec、RuboCop 与调试技巧。
加载本节练习…
← 上一课并发下一课 →测试与质量