SuperAPI AI 工具集

rails-dev

编程与开发

查看项目

更新于 10-16 01:58

技能介绍

用途

rails-dev 是一个面向 Rails 项目的开发约定技能。它被设计为在编写、设计、评审或分析 Rails 代码之前加载,让编码行为遵循一套明确的、有倾向性的约定。资料明确要求:在做设计、写代码、评审或分析之前,应先把任务匹配到对应参考文件并完整阅读,不能只看索引表,也不能凭代码库或通用 Rails 知识猜测。

核心理念

资料列出的核心理念包括:

  • Rich models:业务逻辑放在模型中,而不是 service object 中。
  • Everything is CRUD:用新资源替代新动作,例如用 resource :closure 而不是 post :close。
  • State as records:用 Closure 模型表达关闭状态,而不是 closed: boolean。
  • Concerns for composition:用 Closeable、Watchable、Commentable 等 concern 做组合。
  • Explicit over clever:先内联,直到重复真实发生;抽象要靠理由赢得位置,而不是建立在猜测之上。
  • Small interfaces:没有调用者的公开方法不应存在。
  • Let it crash:使用 bang 方法(如 create!),在边界处理失败,而不是预先防护。
  • Invariants in the schema:硬性规则(presence、uniqueness、范围)用 NOT NULL / unique / check 约束表达;校验用于面向用户的消息,而不是事实来源;引用保持软引用,不使用外键,完整性由模型层保证。
  • Minimal dependencies:先自己实现再考虑 gem。不使用 Devise、Pundit、RSpec、FactoryBot、ViewComponent、service/form object 或装饰器。
  • Database-backed:使用 Solid Queue/Cache/Cable,不使用 Redis。
  • Test coverage:维持大约 1:1 的测试比例(每行代码约一行测试)。

参考文件与任务映射

资料提供了一张索引表,把任务映射到参考文件,并强调约定内容在参考文件中,而不在这张表、代码库或通用 Rails 知识里。对应关系为:模型、校验、关联、业务逻辑对应 references/model.md;自定义校验器与跨模型复用的校验规则对应 references/validator.md;错误处理、rescue 边界、上报、重试对应 references/error-handling.md;控制器与 CRUD 动作对应 references/crud.md;路由与 config/routes.rb 对应 references/routes.md;concern 与共享行为对应 references/concerns.md;状态追踪(非布尔)对应 references/state-records.md;认证、授权、会话、IDOR 作用域对应 references/auth.md;数据库迁移对应 references/migration.md;Minitest、fixtures、测试对应 references/test.md;视图、ERB、partial、helper、展示逻辑对应 references/view.md;Turbo Frames/Streams 与实时对应 references/turbo.md;Stimulus 控制器与 JS 对应 references/stimulus.md;后台任务与 Solid Queue 对应 references/jobs.md;并发、fiber、Async、外部 I/O 对应 references/async.md;Mailer 与邮件通知对应 references/mailer.md;片段缓存与 HTTP 缓存对应 references/caching.md;REST API 与 JSON 响应对应 references/api.md;多租户与账号作用域对应 references/multi-tenant.md;事件追踪与活动日志对应 references/events.md;Webhook(入站/出站)、inbox、幂等对应 references/webhooks.md;代码评审与一致性检查对应 references/review.md;HTTP 客户端、外部 API、Faraday 对应 references/http-client.md;日志与 Rails.logger 对应 references/logging.md。

编码风格规则

资料给出的编码风格规则是跨领域的,适用于所有文件,但不替代参考文件。

条件

对简单分支使用展开的 if/else,而不是带返回值的 guard clause;当方法体非平凡时,方法顶部的 guard clause 是可以的。

# Don't: value-returning guard clause for a simple branch
def status_label
  return "closed" if closed?
  "open"
end

# Do: expanded if/else
def status_label
  if closed?
    "closed"
  else
    "open"
  end
end

方法顺序

类方法在前,然后公开方法(initialize 最前),然后私有方法。方法按调用关系纵向排序:调用者在其被调用者之上。

# Don't: callee above its caller, public after private
class Signup
  def create_member = Member.create!(email:)
  def call = create_member
end

# Do: class method, then the caller, then its callees
class Signup
  def self.call(...) = new(...).call

  def call = create_member

  private
    def create_member = Member.create!(email:)
end

可见性

private 后不留空行;其下的方法缩进。如果模块只有私有方法,则在顶部标记 private 并在其后留一个空行,方法不缩进。

# Don't: blank line after private, methods not indented
class Card
  private

  def closure_exists? = closure.present?
end

# Do: no blank line, indented under private
class Card
  private
    def closure_exists? = closure.present?
end

Bang 方法

仅当存在对应的非 bang 方法(如 save/save!)时才使用 !。绝不为了标记破坏性或重要操作而加 !。

# Don't: unpaired bang used to signal "this is destructive"
def revoke! = update!(revoked_at: Time.current)

# Do: plain domain verb; the ! belongs to the paired persistence call
def revoke = update!(revoked_at: Time.current)

方法命名

公开方法是领域动词。当动词与 scope、谓词或核心方法(Kernel#fail)冲突时,用 mark_ 前缀(不加 bang),例如 mark_failed。类和概念命名见 references/model.md。

# Don't: mark_ prefix when the plain verb is free
def mark_published = update!(published_at: Time.current)

# Do: plain verb; reserve mark_ for a real collision (fail -> Kernel#fail)
def publish = update!(published_at: Time.current)
def mark_failed = update!(failed_at: Time.current)

注释

默认不写注释。大多数注释是噪音:代码和命名应承载含义。仅在代码无法承载时才加一条,例如路径或代码无法说明问题,或模型语言有歧义、需要澄清其在领域中的位置。不要复述代码已经说明的内容,不要写分节注释(如测试中的 # ----- some_method ----- 横幅)。当注释确实有价值时:用平实英语、简洁、不使用 LLM 式词汇,用列表比散文更清晰时用列表。

# Don't: restates what the code already says; section banner
# increment the attempts counter
attempts += 1

# ----- private helpers -----

# Do: explains the non-obvious why
# Circle returns 422 on duplicate emails, so we reconcile instead of recreating.
reconcile_member(email)

错误

不要吞掉错误。让失败对调用者可访问,通常做法是把失败记录在返回对象上,而不是记录日志后返回 false。完整的处理约定(record 还是 raise、上报、包装、重试)见 references/error-handling.md。

# Don't: swallow the error; the caller can't tell it failed
def provision_circle
  circle_client.create_community_member(...)
rescue Circle::AdminClient::ApiError
  false
end

# Do: record the failure on the returned object
def provision_circle
  circle_client.create_community_member(...)
  circle_access.mark_successful(external_id: response.dig(:community_member, :id))
rescue Circle::AdminClient::ApiError => e
  circle_access.mark_failed(error: e.message)   # caller checks access.failed?
end

来源说明

资料说明这些约定改编自以下参考应用,并可能与它们存在差异:basecamp/fizzy、railswhey/app。

限制与未提供信息

资料未提供该技能的安装命令、具体调用方式、支持的平台或版本要求、收费与价格信息;这些内容暂未提供。