Eric Guo's blog.cloud-mes.com

Hoping writing JS, Ruby & Rails and Go article, but fallback to DevOps note

Make Tabnine Continue Work After Official Stop Support the Sublime Text

Permalink

Today I found my TabNine stop working and after 2 hours, I found it officially stop support Sublime Text

But if you having the API key here is how to make it continue work in local mode. Goto '/Users/[username]/Library/Application Support/Sublime Text/Packages' and change 'dl_binaries.sh' as below.

Change targets to your platform if required.

#!/bin/sh
set -e
# This script downloads the binaries for the most recent version of TabNine.
version="4.4.25"
targets='aarch64-apple-darwin'
rm -rf ./binaries
echo "$targets" | while read target
do
mkdir -p binaries/$version/$target
path=$version/$target
echo "downloading $path"
curl -sS https://update.tabnine.com/bundles/$path/TabNine.zip > binaries/$path/TabNine.zip
unzip -o binaries/$path/TabNine.zip -d binaries/$path
rm binaries/$path/TabNine.zip
chmod +x binaries/$path/*
done
binariesver=$(grep -Eo '!binaries/.*' .gitignore | cut -c10-)
sed "s+$binariesver+/$version+g" .gitignore >.gitignore.tmp && mv .gitignore.tmp .gitignore

Run it to download, The 4.4.25 is the most stable version and 4.256.0 is the last known version works with sublime text 4 build 4196.

You need also block update.tabnine.com in hosts file to block TabNine auto upgrade, although codota says you can type TabNine::disable_auto_update.

Known model list and support language

  • Universal Small - ce94127b
  • Universal Medium - b8373e4b
  • cpp_specialized_model - b6e9f0da
  • python - 4caf976f
  • ruby_specialized_model - 29b87067
  • go - 598b1f5b
  • java - af421852
  • rust_specialized_model - 46f17fa1

C#, JS, CSS, HTML and PHP belongs to Universal model

A Rails Developer Installation Log on MacBook M4 Pro

Permalink

I got my fouth MacBook Pro today. It's the second Apple Silicon CPU Mac. I bought in PDD and 48G 1T slightly high-end model.

Mac App Store install list

  • AdBlock Pro (11.2.3)
  • Affinity Designer (2.6.2)
  • Affinity Photo (2.6.2)
  • Affinity Publisher (2.6.2)
  • Aware (1.2.0)
  • Diagrams (2.2.0)
  • Elmedia Video Player (8.1)
  • iA Writer (5.6.16)
  • iMovie (10.3.1)
  • Jump Desktop (9.0.99)
  • Keynote (14.4)
  • LiquidText (2.10.36)
  • Logoist 5 (5.1.2)
  • MockFlow (2.7.9)
  • Numbers (14.4)
  • OwlOCR (4.9.2)
  • Pages (14.4)
  • Paper (95)
  • PasteNow (2.22)
  • Pixelmator Pro (3.6.17)
  • SimpleMind Pro (2.6.1)
  • SQLPro Studio (2025.9)
  • Tampermonkey (5.3.6218)
  • Texifier (1.9.31)
  • Things (3.21.6)
  • WeChat (3.8.10)
  • WeCom (4.1.33)
  • Xcode (16.3)

brew install cask list

  • aldente
  • hype
  • chromedriver
  • ghostty
  • imageoptim
  • rapidapi
  • keybase
  • rar
  • zoom
  • cursor
  • rubymine
  • dash
  • google-chrome
  • sublime-merge
  • discord
  • google-cloud-sdk
  • obs
  • sublime-text

brew install console list

  • bash
  • fzf
  • gdu
  • gh
  • git
  • git-filter-repo
  • git-trim
  • go
  • highlight
  • imagemagick
  • jq
  • libpq
  • memcached
  • mysql-client
  • node
  • percona-server
  • poetry
  • postgresql
  • pytorch
  • redis
  • ruby
  • ruff
  • rust
  • smartmontools
  • tmux
  • vips
  • wget
  • yamllint
  • yarn
  • zoxide

bash-it setup

bash-it enable plugin zoxide proxy base
bash-it enable alias general
bash-it enable completion bash-it brew bundler capistrano cargo aliases export gcloud gem go npm rake ssh system yarn
zoxide init

Some not sign exe file

xattr -dr com.apple.quarantine /opt/homebrew/bin/rar
# put .rarreg.key to ~
xattr -dr com.apple.quarantine /opt/homebrew/bin/chromedriver

.profile

export PATH="/opt/homebrew/opt/ruby/bin:/opt/homebrew/lib/ruby/gems/3.4.0/bin:$PATH:/opt/homebrew/opt/postgresql@17/bin:$HOME/.local/bin:$HOME/.cargo/bin"
export HISTSIZE=80000
export ADBLOCK=true
export HOMEBREW_GITHUB_API_TOKEN=
export HOMEBREW_EDITOR="subl"
export HOMEBREW_NO_INSTALL_CLEANUP=1
export HOMEBREW_AUTO_UPDATE_SECS=1800
export LANG=en_US.UTF-8
export LC_CTYPE=en_US.UTF-8
export EDITOR="vim"
export BUNDLER_EDITOR="subl"
export GEM_EDITOR="subl"
export BASH_IT_HTTP_PROXY=http://127.0.0.1:6152/
export BASH_IT_HTTPS_PROXY=http://127.0.0.1:6152/
export NO_PROXY=localhost,127.0.0.1,.local
export GITHUB_APP_ID=
export GITHUB_APP_SECRET=
export NO_ORACLE_ENHANCED=1
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export MANPATH=/usr/share/man:/opt/homebrew/share/ubuntu_man
export NODE_COMPILE_CACHE=/Users/guochunzhong/.cache/nodejs-compile-cache
export DEVISE_JWT_SECRET_KEY=
export WEFOCUSIN_WECHAT_APPID=
export WEFOCUSIN_WECHAT_SECRET=
export WEFOCUSIN_WECHAT_TOKEN=
export WEFOCUSIN_WECHAT_AES_KEY=
export OPENPROJECT_CORE=/Users/guochunzhong/git/sso/openproject
export DEEPSEEK_ACCESS_TOKEN=sk-
export SWARM_AGENT_DEFAULT_MODEL=deepseek-chat

Please notice ubuntu_man is used by Dash

.bash_profile

#!/usr/bin/env bash
source /Users/guochunzhong/.profile
alias bde='bundle exec'
alias bdc='bundle check'
alias bdpd='bundle exec cap production deploy'
alias glg="git log --graph --pretty=format:'%Cred%h%Crest -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"
alias minio-server='minio server /usr/local/var/minio'
alias convert_screen_cast='ffmpeg -i Screencast.mov -vcodec h264 -acodec mp3 Screencast.mp4'
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return ;;
esac
# Path to the bash it configuration
export BASH_IT="/Users/guochunzhong/.bash_it"
# Lock and Load a custom theme file.
# Leave empty to disable theming.
# location "$BASH_IT"/themes/
export BASH_IT_THEME='inretio'
# Some themes can show whether `sudo` has a current token or not.
# Set `$THEME_CHECK_SUDO` to `true` to check every prompt:
#THEME_CHECK_SUDO='true'
# (Advanced): Change this to the name of your remote repo if you
# cloned bash-it with a remote other than origin such as `bash-it`.
# export BASH_IT_REMOTE='bash-it'
# (Advanced): Change this to the name of the main development branch if
# you renamed it or if it was changed for some reason
# export BASH_IT_DEVELOPMENT_BRANCH='master'
# Your place for hosting Git repos. I use this for private repos.
export GIT_HOSTING='git@git.domain.com'
# Don't check mail when opening terminal.
unset MAILCHECK
# Change this to your console based IRC client of choice.
export IRC_CLIENT='irssi'
# Set this to the command you use for todo.txt-cli
export TODO="t"
# Set this to the location of your work or project folders
#BASH_IT_PROJECT_PATHS="${HOME}/Projects:/Volumes/work/src"
# Set this to false to turn off version control status checking within the prompt for all themes
export SCM_CHECK=true
# Set to actual location of gitstatus directory if installed
#export SCM_GIT_GITSTATUS_DIR="$HOME/gitstatus"
# per default gitstatus uses 2 times as many threads as CPU cores, you can change this here if you must
#export GITSTATUS_NUM_THREADS=8
# Set Xterm/screen/Tmux title with only a short hostname.
# Uncomment this (or set SHORT_HOSTNAME to something else),
# Will otherwise fall back on $HOSTNAME.
#export SHORT_HOSTNAME=$(hostname -s)
# Set Xterm/screen/Tmux title with only a short username.
# Uncomment this (or set SHORT_USER to something else),
# Will otherwise fall back on $USER.
#export SHORT_USER=${USER:0:8}
# If your theme use command duration, uncomment this to
# enable display of last command duration.
#export BASH_IT_COMMAND_DURATION=true
# You can choose the minimum time in seconds before
# command duration is displayed.
#export COMMAND_DURATION_MIN_SECONDS=3
# Set Xterm/screen/Tmux title with shortened command and directory.
# Uncomment this to set.
#export SHORT_TERM_LINE=true
# Set vcprompt executable path for scm advance info in prompt (demula theme)
# https://github.com/djl/vcprompt
#export VCPROMPT_EXECUTABLE=~/.vcprompt/bin/vcprompt
# (Advanced): Uncomment this to make Bash-it reload itself automatically
# after enabling or disabling aliases, plugins, and completions.
# export BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE=1
# Uncomment this to make Bash-it create alias reload.
# export BASH_IT_RELOAD_LEGACY=1
# Load Bash It
source "$BASH_IT"/bash_it.sh
eval "$(/opt/homebrew/bin/brew shellenv)"
eval "$(zoxide init bash)"
export START_DIR="/Users/guochunzhong/git"
if [[ $PWD == $HOME ]]; then
cd $START_DIR
fi

Install macpm

brew install pipx
pipx install macpm

Install relative go tools used in cursor

brew install gopls
brew install staticcheck
brew install dlv

The ghostty config

~/.config/ghostty/config
cursor-style-blink = false
font-size = 12
font-thicken = true
font-thicken-strength = 192
font-family = ""
font-family = "Source Code Pro"
font-family = "Sarasa Term SC"
keybind = global:cmd+ctrl+backquote=toggle_quick_terminal
macos-option-as-alt = true
shell-integration-features = cursor,sudo,title,ssh-env,ssh-terminfo
scrollback-limit = 200000000
theme = modus-vivendi
~/.config/ghostty/themes/modus-vivendi
background = #000000
foreground = #ffffff
palette = 0=#000000
palette = 1=#ff8059
palette = 2=#44bc44
palette = 3=#d0bc00
palette = 4=#2fafff
palette = 5=#feacd0
palette = 6=#00d3d0
palette = 7=#bfbfbf
palette = 8=#595959
palette = 9=#ef8b50
palette = 10=#70b900
palette = 11=#c0c530
palette = 12=#79a8ff
palette = 13=#b6a0ff
palette = 14=#6ae4b9
palette = 15=#ffffff

An AI Roadmap in 2025 for a Midsize non-IT Company Chinese

Permalink

中等规模的非 IT 企业在 2025 年的 AI 应用路线图

人工智能(AI)在过去两年呈爆发式发展,特别是 2024 年 12 月 26 日 DeepSeek V3 模型的发布,标志着中国正式进入 AI 智能时代。对于非 IT 主业的传统企业而言,制定清晰的 AI 战略路线图已成为数字化转型的关键。

目前的 AI 现状与方向选择

DeepSeek V3 为何能成为里程碑

在 DS V3 实现大规模商用前,国内企业面临两大困境:其一,国际主流模型受地缘政策限制难以合规使用;其二,可用模型的调用成本居高不下(单次请求约 0.8 元),严重制约规模化应用。DS V3 通过技术突破将成本降低 40 倍(单次成本约 0.02 元),使企业级应用真正具备经济可行性。

自部署 vs 调用 API

目前看来自部署的唯一优势就是隐私安全,其他完全不能和直接调用厂商 API 比较,调用 DS 的 API,2 月份花费不到 1 元,即使考虑需求在未来增长百倍,一年也不过 1200 元的费用,而一块 4090 的显卡目前价格在 2 万左右,等于可以用几十年。

更重要的是调用 DS API 的模型是 670b 的 V3 或者 R1,从模型参数看,也比单块 4090 跑的 14b 要大 47 倍,而且这个差距不可弥补,使用 AI 最重要的是 AI 的智能,14b 的模型基本等于小学生的智能,而 V3 绝对可以达到大学本科的水平。

自部署的 14b 在实际测试中,对于合同分析的问题,比如“收款条件第一笔是否为预付款,回答是或者否”,令人难以置信的是,硅基流动的线上版本的DeepSeek-R1-Distill-Qwen-14B的思考链效果也远远好于本地部署的Ollama 的 DeepSeek-R1:14b,理论上这两个模型应该是完全一样,实在令人不解。

同时我还在微信群中看到有某单位领导部署 70b 模型后与公网差距巨大的截图,可见即使是完全相同的模型,在部署的时候的一些 knowhow 可能仍然是不公开的。

DeekSeek 在 2025 年 3 月开源第 6 天的X 推文中指出,DS 在部署中可以达到 545% 的理论每天利润率,与此同时,伯克利尤洋却可以算出每月亏损 4 亿的奇怪数字,所以自部署模型无论从经济或者技术角度,可能都不是目前的最佳选择,这至少是目前看到的形式。

RAG vs 模型微调

另外一个存在选择的方向是使用 RAG 搜索嵌入,或者对模型进行微调,这个在网上讨论也是非常多的,目前来看,RAG 的灵活性和实时性要好得多,可以优先尝试,其实这两个方向不存在矛盾,在以后积累了一定的问答数据集后,同样可以对模型进行微调。

但第一优先的仍然应该是 RAG,RAG 的方式方法其实也非常多,在穷尽这些方法前我认为没有必要去看模型微调,尤其是 RAG 很直观,永远能从 Prompt Log 中看到引用了那些知识内容,理论上只要提供的准确的文本信息,模型能力到位,是完全可以得到准确答案的。这种确定性和实时性非常重要。

相比之下模型微调只有在经过很长时间的一段时间的模型调整后才能查看结果,而且若对这次模型调整的新的例子的推理结果不满意的话,又要将准确的例子作为训练素材进行重新微调,一次微调耗时 1~2 天(硅基流动调用频率),显然无法和 RAG 对比实时性。

当然在积累足够量的标注数据(≥1 万条)后,我们仍然可对基础模型进行领域适配。但需注意单次微调周期约 48 小时,且需要持续迭代优化。

另外我们仍然需要考虑模型的优化速度,可能这些微调都没必要做,因为可能当我们的项目做了 3,4 个月后,更优秀的模型早就出了,可能都不用做微调。

直接使用厂商 API vs 通过 AI 中间平台调用

由于 AI 调用的返回极其缓慢,导致直接调用厂商 API 性能收益约等于 0,可能通过 AI 中间平台调用会损失 1 秒,但是相比呼叫 AI 模型厂商动则需要等待 20 多秒的情况,可以忽略不计。

使用 dify 应用开发平台,可以免费获得 prompt 调试环境,API 调用历史分析等功能,同时还可以将 AI 模型调整的工作从较为瓶颈的程序员下放到运营和产品经理身上,甚至最终用户身上,更加便于 AI 的使用者理解 AI 目前的局限性,所以肯定是使用类似 dify 这样的应用开发平台合适。直接调用厂商 API 都没有这些功能。

未来的方向与展望

现在 AI 的瓶颈已经从模型端转移到应用端,对中等规模的非 IT 主业企业来说,最重要的是找到自己公司流程上各个可以运用 AI 智能,降低人力的应用点,逐个补强,至少是用 AI 平替这些点,这样才能在未来 AI 含量越来越高的市场环境中获得成本和反应速度优势,当然是在保持人类智能质量的前提下。

目前我们已经在用的是 7777 IT 服务问答助手,PLM 问答助手,在研发的有 BIM 空间名称识别,合同分析测试,相信还有很多微小的可以用 AI 替代人工的点存在,所以 AI 应用在 2025 年大有可为。

Install Sassc in Sequoia and Brew Ruby 3.4.1

Permalink

My new Sequoia 15.3 seems not loading C++ standard library headers and lead several native gem failed to compile:

┌─[±][master U:1 ✗][ 5:13PM][product_hunt]
└─▪ bundle update
Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Fetching sassc 2.4.0
Installing sassc 2.4.0 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory: /opt/homebrew/lib/ruby/gems/3.4.0/gems/sassc-2.4.0/ext
/opt/homebrew/opt/ruby/bin/ruby extconf.rb
creating Makefile
current directory: /opt/homebrew/lib/ruby/gems/3.4.0/gems/sassc-2.4.0/ext
make DESTDIR\= sitearchdir\=./.gem.20250128-60884-opsqne sitelibdir\=./.gem.20250128-60884-opsqne clean
current directory: /opt/homebrew/lib/ruby/gems/3.4.0/gems/sassc-2.4.0/ext
make DESTDIR\= sitearchdir\=./.gem.20250128-60884-opsqne sitelibdir\=./.gem.20250128-60884-opsqne
compiling ./libsass/src/ast.cpp
In file included from ./libsass/src/ast.cpp:3:
In file included from ./libsass/src/sass.hpp:55:
In file included from ./libsass/src/memory.hpp:8:
./libsass/src/memory/allocator.hpp:8:10: fatal error: 'vector' file not found
8 | #include <vector>
| ^~~~~~~~
1 error generated.
make: *** [ast.o] Error 1
make failed, exit code 2
Gem files will remain installed in /opt/homebrew/lib/ruby/gems/3.4.0/gems/sassc-2.4.0 for inspection.
Results logged to /opt/homebrew/lib/ruby/gems/3.4.0/extensions/arm64-darwin-24/3.4.0/sassc-2.4.0/gem_make.out
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:126:in 'Gem::Ext::Builder.run'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:52:in 'block in Gem::Ext::Builder.make'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:44:in 'Array#each'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:44:in 'Gem::Ext::Builder.make'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/ext_conf_builder.rb:44:in 'Gem::Ext::ExtConfBuilder.build'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:195:in 'Gem::Ext::Builder#build_extension'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:229:in 'block in Gem::Ext::Builder#build_extensions'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:226:in 'Array#each'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/ext/builder.rb:226:in 'Gem::Ext::Builder#build_extensions'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/rubygems/installer.rb:844:in 'Gem::Installer#build_extensions'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/rubygems_gem_installer.rb:111:in 'Bundler::RubyGemsGemInstaller#build_extensions'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/rubygems_gem_installer.rb:30:in 'Bundler::RubyGemsGemInstaller#install'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/source/rubygems.rb:205:in 'Bundler::Source::Rubygems#install'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/installer/gem_installer.rb:55:in 'Bundler::GemInstaller#install'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/installer/gem_installer.rb:17:in 'Bundler::GemInstaller#install_from_spec'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/installer/parallel_installer.rb:133:in 'Bundler::ParallelInstaller#do_install'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/installer/parallel_installer.rb:124:in 'block in Bundler::ParallelInstaller#worker_pool'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/worker.rb:62:in 'Bundler::Worker#apply_func'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/worker.rb:57:in 'block in Bundler::Worker#process_queue'
<internal:kernel>:168:in 'Kernel#loop'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/worker.rb:54:in 'Bundler::Worker#process_queue'
/opt/homebrew/lib/ruby/site_ruby/3.4.0/bundler/worker.rb:90:in 'block (2 levels) in Bundler::Worker#create_threads'
An error occurred while installing sassc (2.4.0), and Bundler cannot continue.
In Gemfile:
sassc-rails was resolved to 2.1.2, which depends on
sassc

Below is the correct solution:

xcrun --show-sdk-path
CPLUS_INCLUDE_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1 bundle install
CPLUS_INCLUDE_PATH=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1 gem install rmmseg-cpp-new

Record the Post Body in Nginx Access Log

Permalink

Sometime, it is easier to debug the Rails program if nginx can record the user's post body and here is how to.

server {
log_format postdata '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'request_body:"$request_body"';
location @puma_rails_production {
client_body_buffer_size 16k;
client_max_body_size 4G;
access_log /var/www/oauth2id/shared/log/nginx.access.log postdata;
proxy_set_header X-Request-Body $request_body;
}
}

Warning: It's not compatible with .NET apps, detail not yet check so recommand only enable during debug.

Import and Export PostgreSQL DB in Gzip Way

Permalink

Export PostgreSQL DB in gzip format

pg_dump open_project_prod -O -x | gzip > open_project_prod_db.sql.gz

Import directly in gzip format

psql -d postgres
DROP DATABASE openproject_development;
CREATE DATABASE openproject_development WITH ENCODING='UTF8';
ALTER DATABASE openproject_development SET TIMEZONE='Asia/Shanghai';
\q
# gunzip < open_project_prod_db.sql.gz | psql -d open_project_ppp --username=op_ppp -W --host=172.17.1.66
gunzip < open_project_prod_db.sql.gz | psql -d openproject_development

Deploy High-Five Rails App on Rocky Linux 9 Using Capistrano

Permalink

Setup high_five user account

adduser high_five
gpasswd -a high_five wheel
cd /etc/sudoers.d
# you can later change more limit like "high_five ALL=(ALL) NOPASSWD:/usr/bin/systemctl"
echo "high_five ALL=(ALL) NOPASSWD:ALL" > 95-high_five-user
sudo su - high_five
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys
chmod 600 .ssh/authorized_keys

Install ruby dep

sudo dnf -y install git make gcc curl openssl-devel zlib-devel libffi-devel readline-devel sqlite-devel postgresql-devel
sudo dnf --enablerepo=crb -y install libyaml-devel gdbm-devel
sudo yum -y install gcc-c++ # required by grpc
sudo yum -y install rust # if need YJIT
sudo yum -y install git-lfs # if any repository using LFS to store picture

Install rbenv and ruby-build

cd # as a high_five
git clone https://git.thape.com.cn/rails/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
~/.rbenv/bin/rbenv init # also edit ~/.bash_profile
# As an rbenv plugin
mkdir -p "$(rbenv root)"/plugins
git clone https://git.thape.com.cn/rails/ruby-build.git "$(rbenv root)"/plugins/ruby-build
git clone https://git.thape.com.cn/rails/rbenv-china-mirror.git "$(rbenv root)"/plugins/rbenv-china-mirror

Install Ruby 3.3.5

rbenv install -l
rbenv install 3.3.5
rbenv global 3.3.5
rbenv shell 3.3.5
echo "gem: --no-document" > ~/.gemrc
gem update --system

Create deploy folder

cd /var/www
sudo mkdir high_five
sudo chown high_five:high_five high_five/

Create DB user and DB

sudo su - postgres
createuser high_five
psql
ALTER ROLE high_five LOGIN;
ALTER USER high_five PASSWORD '';
CREATE DATABASE high_five_prod WITH ENCODING='UTF8' OWNER=high_five;
logout
vi /var/lib/pgsql/16/data/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
host high_five_prod high_five 0.0.0.0/0 scram-sha-256

Reload conf without restart DB

sudo su - postgres
/usr/pgsql-16/bin/pg_ctl reload

The extra file for capistrano

puma

The puma file which will lauch puma via system service.

/var/www/high_five/shared/puma.rb
#!/usr/bin/env puma
directory '/var/www/high_five/current'
rackup "/var/www/high_five/current/config.ru"
environment 'production'
tag ''
pidfile "/var/www/high_five/shared/tmp/pids/puma.pid"
state_path "/var/www/high_five/shared/tmp/pids/puma.state"
stdout_redirect '/var/www/high_five/shared/log/puma_access.log', '/var/www/high_five/shared/log/puma_error.log', true
threads 0,16
bind 'unix:///var/www/high_five/shared/tmp/sockets/puma.sock'
workers 0
restart_command 'bundle exec puma'
prune_bundler
on_restart do
puts 'Refreshing Gemfile'
ENV["BUNDLE_GEMFILE"] = ""
end

systemd service file

/etc/systemd/system/puma_high_five.service
# This file tells systemd how to run Puma as a 24/7 long-running daemon.
#
# Customize this file based on your bundler location, app directory, etc.
# Customize and copy this into /usr/lib/systemd/system (CentOS) or /lib/systemd/system (Ubuntu).
# Then run:
# - systemctl enable puma_high_five
# - systemctl {start,stop,restart} puma_high_five
#
#
# Use `journalctl -u puma_high_five -rn 100` to view the last 100 lines of log output.
#
[Unit]
Description=Puma HTTP Server for high_five (production)
After=syslog.target network.target
[Service]
Type=simple
WatchdogSec=10
User=high_five
WorkingDirectory=/var/www/high_five/current
ExecStart=/home/high_five/.rbenv/bin/rbenv exec bundle exec --keep-file-descriptors puma -C /var/www/high_five/shared/puma.rb
ExecReload=/bin/kill -USR1 $MAINPID
# if we crash, restart
RestartSec=1
Restart=on-failure
StandardOutput=append:/var/www/high_five/shared/log/puma.log
StandardError=append:/var/www/high_five/shared/log/puma.log
SyslogIdentifier=puma_high_five
[Install]
WantedBy=multi-user.target

nginx conf files

/etc/nginx/conf.d/high_five.conf
upstream puma_high_five_production {
server unix:/var/www/high_five/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
if ($host = high-five.thape.com.cn) {
return 301 https://$host$request_uri;
}
listen 80;
server_name high-five.thape.com.cn;
return 301 https://$host$1$request_uri;
}
server {
listen 443 ssl http2;
ssl_certificate /etc/ssl/cert/STAR_thape_com_cn_integrated.crt;
ssl_certificate_key /etc/ssl/private/STAR_thape_com_cn.key;
server_name high-five.thape.com.cn;
root /var/www/high_five/current/public;
try_files $uri/index.html $uri @puma_high_five_production;
client_max_body_size 4G;
keepalive_timeout 10;
error_page 500 502 504 /500.html;
error_page 503 @503;
location @puma_high_five_production {
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://puma_high_five_production;
# limit_req zone=one;
access_log /var/www/high_five/shared/log/nginx.access.log;
error_log /var/www/high_five/shared/log/nginx.error.log;
}
location ~ (/manifest.json|/favicon.ico|/*.txt|/*.png) {
access_log off;
expires 3d;
gzip_static on;
add_header Cache-Control public;
}
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location = /50x.html {
root html;
}
location = /404.html {
root html;
}
location @503 {
error_page 405 = /system/maintenance.html;
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html break;
}
rewrite ^(.*)$ /503.html break;
}
if ($request_method !~ ^(GET|HEAD|PUT|PATCH|POST|DELETE|OPTIONS)$ ){
return 405;
}
if (-f $document_root/system/maintenance.html) {
return 503;
}
}

How to Start Learning Ruby on Rails Chinese 2024 Edition

Permalink

作者背景

任何一门劝人入坑的文章大家都要注意背景,比如有些 Google 的雇员,因为要推广 Flutter,会把 Flutter 的能力写的花好稻好,然后最近直接团队被裁员,只留下误导新人的一篇篇文章,当然,我也得承认我写的这篇肯定也存在误导,但是我可以发自内心的表示,我至少绝对不是有意为之,我书写本文的目的因为我本身比较喜欢 Ruby 的自由,还有 Rails 的高开发效率。另外从 2012 年全面转向使用 Ruby on Rails 编程以来,它也给了我一份相对不错的工作。

TLDR

  • 若您认为计算机语言书写的代码必须带有类型标记,那么本文不适合您,如果您不知道前面一句话啥意思,可以继续阅读;
  • 若您认为前后端使用同一种语言可以少学一门语言,并且团队内更容易协作或者相互替换,那么本文不适合您,我推荐 Next.js,请注意,它背后的母公司 Vercel 以卖 deploy/host 为主业,所以以后的应用发布要达到完美状态,您需要在 Deploy 上付出比学习 Rails 更多的努力,另外您需要书写的代码量也会稍微偏多至少 2~3 倍。
  • 若您现在急需转码,找工作,那么我推荐 Python,Python 在数据处理/AI 上的工作岗位比 Ruby 要多很多,是您更好的选择,另外友情提示不要学 Java,这个赛道人数已经卷爆了。
  • 若您比较注重程序写好后的运行效率(Web 服务需要单机 200 request/s 以上,约等于一个细分赛道的 SaaS 软件提供商所需的正常 Web 请求处理能力的 10 倍左右),那么我推荐 Go,Go 配合 Next.js 是很好的前后端选择。

正文开始

环境准备

有钱上 Mac,直接 brew install ruby,然后安装 rails,没钱用 Ubuntu 的 omakub,当然我也知道用 Linux 的用户绝对不会按照我推荐的 omakub,尽量不要在 windows 上搞 Rails,不是不行,坑太多,实在要搞,用 WSL 和直接用 ubuntu 类似。

快速入门

此快速入门不会导致后期的练功反噬,请放心学习。

请直接阅读官方的guide 最新版本开始,中文的手册版本到 Rails 5.1,还是推荐英语。

官方手册是最快速最正统的导览,后端的功能基本上都提到了,原先可能还需要阅读一下《The Rails Way》,目前是第七版,不过这个是可选。

快速入门阶段最好不要过于扣细节,比如belongs_tohas_many是从哪里来的,是方法的话,在哪里定义的之类的框架细节,尽量将 Rails 作为一种 web 应用的定义语言(只是它恰好可以让计算机运行和发布成 web 应用)使用。

官方 Guide 没有提及任何的自动测试内容,这是对的,但是若您接下来就要接手或者开始维护,开发一个真实的 Rails 应用,《Rails Tutorial 6th 6.1.3.p1 中文版本》推荐一读,因为真实的应用多多少少都有一些 TDD 的内容,不过这只是可选。

另外的一个选择是《Agile Web Development with Rails 7.2》,也是半官方的教材,内容更加深入一些,已经不单单是一个入门教材了。

深入 Ruby

当没有完成 Guide 的整个流程前,请不要深入 Ruby 学习,因为这样会不必要的减少您学习 Rails 的时间。

当您开始对诸如1.day.ago之类的 Rails 调用感到惊奇时,您可以考虑学习一点 Ruby 语言的知识,注意 Ruby 语言语法比 JavaScript 还要复杂,所以不要过于钻牛角尖,《Ruby 基础教程》第四版就是很好的入门。

权威性的 Ruby 教材是《Programming Ruby 3.3 5th》,只有英语版本。

入门后的前端选择

不必深入 Ruby 也可以进行以下任意方向的学习

Rails 主要是一门后端框架,核心是 Active Record,还有一些 MVC 架构的约定,入门的定义是对这些已经掌握了,但是 Rails 毕竟是一种全栈的 Web 开发框架,相比后端,在前端的选择是非常非常多的。

抛去目前被废弃的 rails-ujs,Rails 出场自带的前端框架是 turbo / stimulus,若您没有任何的前端经验,推荐学习这套。

Rails 也同时支持Webpack 集成(顺带也支持了 React/Selte/Angular),Rails 也有Vite/Vue.js的支持。

若您有传统的 JSP/ASP.net MVC 程序员背景,更喜欢比较成熟的框架,Bootstrap 的支持也有现成模版,注意这个模版是笔者维护,并且使用了 coreui.io 的扩展,若您喜欢纯官方的,也可以自行封装。

《Modern Front End Development for Rails 2nd》也有助于对整个 Rails 前端生态有更多了解,但是这已经不是入门内容了。

入门后的 API 支持

Rails 支持 Restful 类型的 API,OpenAPI 3.0 规范 或者 GraphQL。

入门后若要进行 API 书写,推荐直接使用官方的 jbuilder 即可,OpenAPI 3.0 需要学习 grape,GraphQL 需要学习 gem graphql。

入门后的部署选择

传统的 VPS 笔者还是推荐 capistrano,若您对 docker 有偏好,可以使用 kamal 2

进阶

Active Cable 基于实时双向的交互值得学习,想更深入也可以看一下 AnyCable,Bug 较多,但是性能更好。《Advanced CableReady》一书可以阅读

一些高阶的 Postgresql 数据库的特性也值得学习,Active Record 虽然非常强了,但是直接裸写 SQL 有时候更加方便。《High performance Postgresql for Rails》推荐。《Pganalyze Efficient Search in Rails with Postgres》也可以阅读。

代码风格

《Ruby Science》by thoughtbot 可以阅读,不过我还是劝您不要花时间在这里,ruby 是很自由的语言,搞一下 standard 的代码风格检查已经做的有点过了。