ruby-conventions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRuby Conventions
Ruby 约定规范
Service objects, strong params, behavior-focused tests.
服务对象、Strong Params、以行为为核心的测试。
Architecture
架构设计
Service objects for business logic:
ruby
undefined使用服务对象处理业务逻辑:
ruby
undefinedapp/services/user_registration_service.rb
app/services/user_registration_service.rb
class UserRegistrationService
def initialize(user_params:, mailer: UserMailer)
@user_params = user_params
@mailer = mailer
end
def call
user = User.create!(@user_params)
@mailer.welcome(user).deliver_later
user
end
end
**Thin controllers:**
```ruby
def create
user = UserRegistrationService.new(user_params: user_params).call
render json: UserSerializer.new(user), status: :created
rescue ActiveRecord::RecordInvalid => e
render json: { errors: e.record.errors }, status: :unprocessable_entity
endclass UserRegistrationService
def initialize(user_params:, mailer: UserMailer)
@user_params = user_params
@mailer = mailer
end
def call
user = User.create!(@user_params)
@mailer.welcome(user).deliver_later
user
end
end
**轻量控制器:**
```ruby
def create
user = UserRegistrationService.new(user_params: user_params).call
render json: UserSerializer.new(user), status: :created
rescue ActiveRecord::RecordInvalid => e
render json: { errors: e.record.errors }, status: :unprocessable_entity
endStrong Parameters
Strong Parameters(强参数)
Always use strong params. Never mass-assign directly:
ruby
undefined始终使用强参数,切勿直接批量赋值:
ruby
undefinedGood
Good
def user_params
params.require(:user).permit(:email, :name, :password)
end
def user_params
params.require(:user).permit(:email, :name, :password)
end
Never
Never
User.create(params[:user]) # SQL injection risk
undefinedUser.create(params[:user]) # SQL injection risk
undefinedQuery Safety
查询安全性
Always parameterize queries:
ruby
undefined始终使用参数化查询:
ruby
undefinedGood
Good
User.where(email: email)
User.where("email = ?", email)
User.where(email: email)
User.where("email = ?", email)
Never
Never
User.where("email = '#{email}'") # SQL injection
**Prevent N+1 queries:**
```rubyUser.where("email = '#{email}'") # SQL injection
**避免N+1查询问题:**
```rubyGood
Good
User.includes(:posts).each { |u| u.posts.count }
User.includes(:posts).each { |u| u.posts.count }
Bad (N+1)
Bad (N+1)
User.all.each { |u| u.posts.count }
undefinedUser.all.each { |u| u.posts.count }
undefinedTesting with RSpec
使用RSpec进行测试
ruby
RSpec.describe UserRegistrationService do
describe "#call" do
it "creates active user with welcome email" do
mailer = instance_double(UserMailer)
allow(mailer).to receive(:welcome).and_return(double(deliver_later: true))
service = described_class.new(
user_params: { email: "test@example.com", name: "Test" },
mailer: mailer
)
user = service.call
expect(user).to be_persisted
expect(user.email).to eq("test@example.com")
expect(mailer).to have_received(:welcome).with(user)
end
end
endUse FactoryBot, not fixtures:
ruby
FactoryBot.define do
factory :user do
email { Faker::Internet.email }
name { Faker::Name.name }
end
end
let(:user) { create(:user) }ruby
RSpec.describe UserRegistrationService do
describe "#call" do
it "creates active user with welcome email" do
mailer = instance_double(UserMailer)
allow(mailer).to receive(:welcome).and_return(double(deliver_later: true))
service = described_class.new(
user_params: { email: "test@example.com", name: "Test" },
mailer: mailer
)
user = service.call
expect(user).to be_persisted
expect(user.email).to eq("test@example.com")
expect(mailer).to have_received(:welcome).with(user)
end
end
end使用FactoryBot,而非fixtures:
ruby
FactoryBot.define do
factory :user do
email { Faker::Internet.email }
name { Faker::Name.name }
end
end
let(:user) { create(:user) }API Design
API 设计
ruby
undefinedruby
undefinedConsistent serialization
Consistent serialization
class UserSerializer
include JSONAPI::Serializer
attributes :id, :email, :name, :created_at
end
class UserSerializer
include JSONAPI::Serializer
attributes :id, :email, :name, :created_at
end
Versioned routes
Versioned routes
namespace :api do
namespace :v1 do
resources :users
end
end
undefinednamespace :api do
namespace :v1 do
resources :users
end
end
undefinedLanguage Patterns
语言模式
ruby
undefinedruby
undefinedKeyword arguments for 2+ params
Keyword arguments for 2+ params
def send_email(to:, subject:, body:)
...
end
def send_email(to:, subject:, body:)
...
end
Safe navigation
Safe navigation
user&.profile&.avatar_url
user&.profile&.avatar_url
Frozen strings (file header)
Frozen strings (file header)
frozen_string_literal: true
frozen_string_literal: true
undefinedundefinedAnti-Patterns
反模式
- Fat models (business logic in ActiveRecord)
- Business logic in controllers
- Fixtures instead of factories
- Testing implementation (mocking internals)
- String interpolation in SQL
- N+1 queries without includes
- Synchronous email in request cycle
- 臃肿模型(将业务逻辑放在ActiveRecord中)
- 在控制器中编写业务逻辑
- 使用fixtures而非工厂模式
- 测试实现细节(模拟内部逻辑)
- 在SQL中使用字符串插值
- 未使用includes导致N+1查询
- 在请求周期中同步发送邮件
References
参考资料
- rails-performance.md - Caching, background jobs, profiling
- rails-performance.md - 缓存、后台任务、性能分析