hitobito 2.10 常用 CLI 与运维命令详解
详解 hitobito 2.10 的 rails/rake 命令入口、235 个任务中的运维主线(数据库、wagon、作业队列、配置自检、webpacker 编译)与 curl/API 调用,全部回显实测。
hitobito 2.10 常用 CLI 与运维命令详解
目标:把 hitobito 2.10 日常运维用得最多的命令行入口(rails、rake 任务体系、hitobito 专属任务、作业队列、HTTP 探活与 API 调用)逐条讲清语法、参数与真实回显。本文全部命令与输出在已部署 hitobito 2.10.0 的 Ubuntu 22.04 服务器实测(应用目录
/opt/hitobito/app,服务地址http://localhost:8152,演示账号admin@hitobito.ch/q1w2e3r4)。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS(x86_64);应用 hitobito core 2.10.0,wagon
generic - 运行时:Ruby 3.3.13、Rails 8.0.5、Bundler 4.0.13、Rake 13.4.2(
rails runner实测读取) - 依赖:PostgreSQL 16(库
hitobito_development)、Redis 8、Node v22.23.4 + yarn 1.22.22(前端编译任务用) - 所有应用侧命令均在应用目录执行:
$ cd /opt/hitobito/app
$ bundle exec rake db:version
database: hitobito_development
Current version: 20260701094113
二、工具概览
hitobito 没有独立发布的 CLI 二进制,运维命令面由四层构成:
| 层 | 入口 | 实测规模 | 典型用途 |
|---|---|---|---|
| Rails 命令 | bundle exec rails <cmd> | runner/console/routes/secret 等 | 脚本化查询、路由核对、密钥生成 |
| Rake 任务 | bundle exec rake <task> | rake -T 实测 235 个任务 | 数据库迁移/种子、wagon、作业队列、业务维护 |
| hitobito 专属任务 | bundle exec rake hitobito:* / wagon:* / db:* 扩展 | 见第四章 | 配置自检、角色树打印、结构解析 |
| HTTP 运维 | curl 会话登录 / JSON:API + Bearer | /healthz、/api/* | 探活、自动化取数 |
💡 技术拓展:Rails 应用的脚本入口不止一种——
入口 加载程度 适合 rails runner script.rb完整应用环境(含连接池、initializer) 查库、调模型、一次性修复脚本 rails console完整环境 + IRB 交互 探索式排查 rake task完整环境 + 任务注册表 可复用的标准化运维动作 ruby -e裸脚本无 Rails 不适合业务操作(绕过模型校验) 本文实测主线用
bundle exec rails runner(只读统计)与bundle exec rake(标准任务),裸 Ruby 不触碰业务数据。
三、前置条件
- 应用目录内执行且带
bundle exec前缀(上游规范明确要求,避免 rake/rspec 命中系统旧版 gem); - 本实例设了
DISABLE_SPRING=true(实测环境文件),脚本命令不会读到预加载缓存的旧代码; - 一次性 Ruby 脚本放应用
tmp/目录下引用(实测形态:bundle exec rails runner tmp/api_token.rb); curl可用(HTTP 验证与 API 调用)。
四、各工具详解
4.1 rails 命令入口
rails runner——本文统计类回显全部由它产生(实测):
$ bundle exec rails runner 'puts "Rails: #{Rails.version} Ruby: #{RUBY_VERSION} Env: #{Rails.env}"'
Rails: 8.0.5 Ruby: 3.3.13 Env: development
$ bundle exec rails runner 'puts "Person: #{Person.count} Event: #{Event.count} Group: #{Group.count}"'
Person: 224 Event: 79 Group: 29
rails secret——生成 128 位 hex 密钥(SECRET_KEY_BASE 用,实测):
$ bundle exec rails secret
1198ab6d94a0aa8d930ff6784aecfedf33384709f66446d2cc82f22763e0151b93d9c94d8e603ca02af0d324eb092efaa7545fee5213a9da6a8e03cbe6ea5126
rails routes——路由普查(实测全量 545 行,节选 API 与健康检查相关行,空白对齐已去除):
root GET / dashboard#index
healthz GET /healthz(.:format) healthz#show
healthz_mail GET /healthz/mail(.:format) healthz/mail#show
healthz_truemail GET /healthz/truemail(.:format) healthz#show
people GET /api/people(.:format) json_api/people#index {:format=>"jsonapi"}
GET /api/groups(.:format) json_api/groups#index {:format=>"jsonapi"}
POST /api/roles(.:format) json_api/roles#create {:format=>"jsonapi"}
4.2 rake 任务体系总览
$ bundle exec rake -T | wc -l
235
rake -T 输出含任务名与官方说明,下面各小节引用的说明行均为该实测输出原文。注意输出前后会夹带启动噪音行(实测):Initializing the Sentry background worker with 3 threads、退出时 Shutting down background worker——配置了 Sentry 时属正常现象。
代码统计(实测节选):
$ bundle exec rake stats
| Controllers | 12892 | 9078 | 174 | 1474 | 8 | 4 |
| Models | 13681 | 7878 | 135 | 1142 | 8 | 4 |
(其余分类行略,输出节选)
Code LOC: 34519 Test LOC: 89518 Code to Test Ratio: 1:2.6
4.3 数据库维护任务
核心说明行(rake -T 实测原文):
rake db:reseed # Empties the database and loads the seeds again
rake db:truncate # Deletes all data from the database, but keeps the tables
rake db:import[backup_filename] # Import a dump and run migrations
rake db:rebuild_nested_set # Rebuild Nested-Set
rake db:resort_groups # Move Groups in alphabetical order
rake db:migrate:status_all # Display status of migrations including the originating wagon name
rake db:seed:all # Load core and wagon seeds into the current environment's database
rake db:seed:development[wagon] # Load development seed files of a wagon
rake db:setup:all # Create the database, load the schema, initialize with the seed data for core and wagons
rake db:sessions:trim # Trim old sessions from the table (default: > 30 days)
rake db:version # Retrieve the current schema version number
实测执行过的两条:
$ bundle exec rake db:version
database: hitobito_development
Current version: 20260701094113
⚠️ 注意:
db:reseed/db:truncate/db:import均为销毁性操作(清空重灌/清数据/覆盖导入),只允许在演示与测试实例上执行;生产数据操作前先做数据库备份。db:sessions:trim则是日常清理任务(默认清 30 天前的会话),适合挂 cron。
4.4 wagon 扩展任务套件
wagon 是 hitobito 的组织定制包(Rails engine 变体),其迁移/种子独立于核心。说明行实测原文:
rake wagon:list # List the loaded wagons
rake wagon:migrate # Run wagon migrations (options: VERSION=x, WAGON=abc)
rake wagon:migrate:status # Display status of migrations including the originating wagon name
rake wagon:seed # Seed wagon data (options: WAGON=abc)
rake wagon:unseed # Unseed wagon data (options: WAGON=abc)
rake wagon:setup # Migrate and seed wagons
rake wagon:exec # Execute CMD in WAGON's base directory
rake wagon:file # Creates a Wagonfile for development
rake wagon:file:prod # Create a Wagonfile for production
rake wagon:schema_dump # Dump schema and schema diff for loaded wagons
rake wagon:app_version # Generate an initializer to set the application version
rake wagon:test # Run the tests of WAGON
实测执行:
$ bundle exec rake wagon:list
generic
要点:wagon 迁移版本与核心迁移分开记账,升级 wagon 后跑 wagon:migrate 而非只跑 db:migrate;核对全部迁移状态用 db:migrate:status_all(说明行实测含 "including the originating wagon name")。
4.5 后台作业命令(Delayed::Job)
说明行实测原文:
rake jobs:work # Start a delayed_job worker
rake jobs:workoff # Start a delayed_job worker and exit when all available jobs are complete
rake jobs:clear # Clear the delayed_job queue
rake jobs:check[max_age] # Exit with error status if any jobs older than max_age seconds haven't been attempted yet
rake delayed_job:check # Check if all expected jobs are scheduled
rake delayed_job:clear # Clear all scheduled Background-Jobs
rake delayed_job:schedule # Schedule Background-Jobs
worker 启动与处理实测日志节选:
$ bundle exec rake jobs:work
[Worker(host:d24d2888c23f pid:1)] Job WalletSynchronizationJob (id=192) COMPLETED after 0.0068
1 jobs processed at 108.4782 j/s, 0 failed
jobs:check 60 语义是"有超过 60 秒未被执行的作业就以非零码退出",可直接接监控告警;另有 delayed:heartbeat:delete_timed_out_workers 等心跳清理任务(实测存在于 235 任务清单)。
💡 技术拓展:Delayed::Job 队列观测方式对比——
方式 手段 特点 任务级 jobs:check[max_age]无额外组件,适合 cron/监控探针 数据库直查 查 delayed_jobs表(PostgreSQL)灵活,需 SQL Web UI(EJL/delayed_job_web 等第三方面板) 挂 Rails 路由 直观,需加 gem 与鉴权 指标导出 Prometheus exporter(hitobito 实测有 PROMETHEUS_EXPORTER_HOST/PORT参数引用)接现有监控栈 本文实测用任务级
jobs:check与 worker 日志两种,未引入第三方面板。
4.6 hitobito 专属业务任务
说明行实测原文:
rake hitobito:check_config # Check existence of needed configurations and settings
rake hitobito:roles[with_classes] # Print all groups, roles and permissions
rake hitobito:abilities # Print all abilities
rake hitobito:parse_structure[filename] # Parse Structure and output classes and translations
rake event:refresh_participant_counts[year] # Refresh all participant_counts in year (defaults to current year)
rake address:import # Import Post Addresses
rake cleanup:deleted_people[group_id] # Remove all people without active roles (deleted_people) in one go
配置自检(发布前检查推荐,实测末行):
$ bundle exec rake hitobito:check_config
...(逐项检查输出,实测节选)
✅ SelfRegistrationRoleTypes configured correctly
角色/权限树打印(实测节选,generic 组织):
$ bundle exec rake hitobito:roles
* Hauptebene
* Hauptebene
* Administrator*in: [:admin, :layer_and_below_full, :impersonation]
* Vorstand
* Präsident*in: [:layer_full, :contact_data]
* Kassier*in: [:layer_read, :contact_data, :finance]
* Geschäftsstelle
* Leitung: [:layer_and_below_full, :admin, :contact_data, :approve_applications, :finance]
* Mitglieder
* Adressverwaltung: [:group_and_below_full]
* Aktivmitglied: []
* Passivmitglied: []
该输出是排查"某角色为什么看不到某菜单"的第一手材料:权限名(layer_and_below_full 等)按组层级切片。hitobito:abilities 则打印展开后的完整 ability 规则。
4.7 前端编译任务(webpacker)
2.10.0 的资产任务只有 webpacker:* 系列(实测原文):
rake webpacker:compile # Compile JavaScript packs using webpack for production with digests
实测直接编译在 Node v22.23.4 下失败(webpack 4 的 md4 哈希被 OpenSSL 3 拒绝,报错节选):
Error: error:0308010C:digital envelope routines::unsupported
library: 'digital envelope routines', reason: 'unsupported', code: 'ERR_OSSL_EVP_UNSUPPORTED'
Node.js v22.23.4
加兼容参数后编译成功(实测节选):
$ NODE_OPTIONS=--openssl-legacy-provider bundle exec rake webpacker:compile
Compiling...
Version: webpack 4.46.0
Time: 22506ms
Built at: 11/01/2026 3:37:57 PM
css/application-f460fb4e.css 340 KiB [emitted] [immutable] [big] application
成功标志为 Compiled all packs 与 public/packs/manifest.json 生成;页面资源实测 GET /packs/css/application-f460fb4e.css 返回 200。
4.8 HTTP 运维命令(curl)
探活(实测):
$ curl -s -i http://localhost:8152/healthz | head -3
HTTP/1.1 200 OK
x-frame-options: SAMEORIGIN
x-xss-protection: 0
会话登录(表单字段实测为 person[login_identity]/person[password]/person[remember_me]):
$ TOKEN=$(curl -s -c cookies.txt http://localhost:8152/de/users/sign_in | \
python3 -c 'import sys,re; print(re.search(r"name=\"authenticity_token\" value=\"([^\"]+)\"", sys.stdin.read()).group(1))')
$ curl -s -b cookies.txt -c cookies.txt -i -X POST http://localhost:8152/de/users/sign_in \
--data-urlencode "authenticity_token=$TOKEN" \
--data-urlencode "person[login_identity]=admin@hitobito.ch" \
--data-urlencode "person[password]=q1w2e3r4" \
--data-urlencode "person[remember_me]=0" | head -1
HTTP/1.1 303 See Other
CSRF 令牌实测长 86 字符,必须整段正则提取;用 grep+cut 截断会 422。登录后验证会话:
$ curl -s -b cookies.txt http://localhost:8152/de/groups/1 | grep -o '<title>[^<]*</title>'
<title>hitobito - Dachverband</title>
令牌生成(rails runner 一次性脚本,实测):
# tmp/api_token.rb
app = Doorkeeper::Application.first || Doorkeeper::Application.create!(name: 'doc-cli', redirect_uri: 'urn:ietf:wg:oauth:2.0:oob')
admin = Person.find_by!(email: 'admin@hitobito.ch')
token = Doorkeeper::AccessToken.create!(application: app, resource_owner_id: admin.id, scopes: 'people events groups', expires_in: 7200)
puts "TOKEN=#{token.token}"
$ bundle exec rails runner tmp/api_token.rb
TOKEN=PpFp2pm9lvbrt7P1V4VjvX0LBRXTd13IWxsl5MnmB84
$ API_TOKEN=PpFp2pm9lvbrt7P1V4VjvX0LBRXTd13IWxsl5MnmB84 # 取上一步回显值
API 取数(JSON:API,实测):
$ curl -s http://localhost:8152/api/people
{"errors":[{"code":"unauthorized","status":"401","title":"Login benötigt","detail":"Du must dich einloggen bevor du auf diese Resource zugreifen kannst.","meta":{}}]}
$ curl -s -H "Authorization: Bearer $API_TOKEN" -H "Accept: application/vnd.api+json" \
http://localhost:8152/api/people | head -c 300
{"data":[{"id":"1","type":"people","attributes":{"first_name":"Puzzle","last_name":"ITC","nickname":null,"company_name":"Puzzle ITC","company":true,"email":"hitobito@puzzle.ch","address":null,(输出节选)
💡 技术拓展:hitobito 实测存在三种 API 认证通道——
通道 请求头 适用 浏览器会话 Cookie(Devise 登录后) 页面自动化冒烟 OAuth2 访问令牌 Authorization: Bearer <API_TOKEN>第三方应用/脚本(OpenAPI 的 ServiceTokenAuthHeader等方案实测见/api/openapi)服务令牌 X-TOKEN实例间服务调用(OpenAPI securitySchemes 声明) 本文脚本主线用 Bearer 通道(令牌由上方 runner 脚本生成,实测有效期 7200 秒)。
五、注意事项
- 一律
bundle exec前缀:上游规范明确要求(裸rake/rspec可能命中系统 gem 版本); - 销毁性任务隔离:
db:reseed、db:truncate、jobs:clear、cleanup:deleted_people执行前确认RAILS_ENV与目标库(rake db:version实测会回显库名,先看再动手); - wagon 与核心迁移双轨:升级定制包记得
wagon:migrate,状态核对用db:migrate:status_all; - 任务清单里的测试/CI 项(如
wagon:test、airbrake:test)不要在生产盲跑; - 开发工具箱仓库另附
bin/辅助脚本(dump_database、load_database、reset_database 等 16 个),属开发环境工具,不随应用发布,生产运维以上述 rake/rails 任务为准; rails runner脚本放tmp/目录属一次性用法,长期脚本请纳入版本管理。
六、常见问题
6.1 rake -T 找不到 assets:watch_js / assets:precompile 行为与文档不符
实测报错原文:
rake aborted!
Don't know how to build task 'assets:watch_js' ... Did you mean? assets:clean
根因:assets:watch_js/watch_css 只存在于上游 master 的新资产管线;2.10.0 release 的资产任务是 webpacker:*(实测 rake -T 仅有 webpacker 系列)。按 4.7 用 webpacker:compile,并确认代码检出版本与所用构建环境配套。
6.2 webpacker:compile 报 ERR_OSSL_EVP_UNSUPPORTED
Node 17+ 的 OpenSSL 3 不支持 webpack 4 的 md4 哈希。实测解法:命令前加 NODE_OPTIONS=--openssl-legacy-provider(4.7 实测成功回显)。长期方案是升级代码到使用新构建管线的版本。
6.3 curl 登录总是 422
CSRF 令牌提取不完整。实测令牌 86 字符,用 4.8 的 python 正则整段提取;同时确认 cookie jar(-c/-b cookies.txt)在取页与提交两步之间复用。
6.4 API 调用返回 401 或 404
401:缺 Authorization: Bearer + Accept: application/vnd.api+json(实测 401 错误体原文见 4.8)。404:实测 .json 后缀路径(如 /api/people.json)不存在——No route matches [GET] "/api/people.json",媒体类型只能走 Accept 头。
6.5 任务输出混入 SQL 日志和 Sentry 噪音
generic 演示环境开发态默认打印 SQL(实测 hitobito:check_config 输出中夹带 Group Load (0.3ms) SELECT "groups"."id", "groups"."parent_id", ... 这类查询行,节选)。核对结果时按行过滤(如 | tail -1 取末行结论),或提高 RAILS_LOG_LEVEL;生产环境日志级别默认更安静。
七、参考链接
- hitobito 仓库(
lib/tasks/任务定义源码):https://github.com/hitobito/hitobito - 官方开发工具箱:https://github.com/hitobito/development
- Delayed::Job:https://github.com/collectiveidea/delayed_job
- webpacker:https://github.com/rails/webpacker
- JSON:API 规范:https://jsonapi.org
- Doorkeeper(OAuth2 提供方):https://github.com/doorkeeper-gem/doorkeeper
- Rails 命令行指南:https://guides.rubyonrails.org/command_line.html