Rectify Form 深度上下文:用 with_context 让嵌套表单轻松共享用户信息
2026/9/19 4:58:49 网站建设 项目流程

Rectify Form 深度上下文:用 with_context 让嵌套表单轻松共享用户信息

【免费下载链接】rectifyBuild maintainable Rails apps项目地址: https://gitcode.com/gh_mirrors/re/rectify

Rectify是一个让 Rails 应用更易于维护的轻量级 Ruby Gem,其核心组件Form Object(表单对象)负责输入数据的校验与管理。本文聚焦 Rectify Form 的with_context方法:只需一行代码,就能把「当前登录用户」等上下文信息注入根表单,并自动传递到所有嵌套表单与表单数组中,让深层校验轻松拿到用户信息。

🧩 痛点:嵌套表单里拿不到"当前用户"吗?

Rectify 的设计观点是把职责拆得清清楚楚:

  • 控制器只处理 HTTP 相关的事
  • 模型只负责数据关系
  • 校验规则和业务逻辑交给Form Object

但很多校验离不开「当前请求」的信息——比如「这篇博客必须是当前用户自己的」。此时根表单还不难拿到current_user,可一旦表单出现嵌套结构(子表单)或表单数组,问题就来了:

子表单与父表单之间没有引用链,它无法"向上"向父表单索要数据。

这正是with_context要解决的"深度上下文"问题。

⚡ 一行注入:with_context 快速上手

在控制器里构造表单时,链式调用即可:

form = UserForm.from_params(params).with_context(user: current_user)

之后在表单任意位置都能通过context读取:

class UserForm < Rectify::Form attribute :first_name, String validate :check_ownership def check_ownership # 表单内部直接通过 context.user 访问当前用户 end end

它的实现位于lib/rectify/form.rb

  • with_context(第 117–131 行):传入 Hash 时会转成OpenStruct存储,非 Hash 对象则原样保存
  • context(第 6 行):只读访问器,任何层级的表单都能调用

💡 小贴士:with_context接受任意对象。传 Hash 时用context.user这类属性方式访问;直接把current_user对象传进去也完全合法。

🌲 深层传播:嵌套表单与表单数组自动继承

with_context不只是给根表单自己用,它会沿着两条线自动向下传播:

  1. 嵌套表单属性(如SchoolForm内嵌TeacherForm
  2. 表单数组属性(如UserForm.contacts声明为Array[ContactForm]

以项目自带的测试 fixture 为例:

# spec/fixtures/forms/school_form.rb class SchoolForm < Rectify::Form attribute :head, TeacherForm # 嵌套表单 end # spec/fixtures/forms/user_form.rb(节选) class UserForm < Rectify::Form attribute :address, AddressForm # 嵌套表单 attribute :contacts, Array[ContactForm] # 表单数组 end

调用之后,每一层表单都能拿到同一份上下文:

form = SchoolForm.new(head: TeacherForm.new(name: "")) .with_context(account_id: 1) form.head.context.account_id # => 1 form.contacts.first.context.account_id # => 1(表单数组同理)

相关验证用例在spec/lib/rectify/form_spec.rb#with_context描述块(第 533–557 行),正好覆盖了根表单、嵌套表单、表单数组三种场景,可以放心参考。

🛡️ 实战:在表单内校验资源归属

readme.md的 "Deep Context" 章节给出的经典场景——发帖时校验博客归属:

class PostForm < Rectify::Form attribute :blog_id, Integer attribute :tags, Array[TagForm] validate :check_blog_ownership def check_blog_ownership return if context.user.blogs.exists?(id: blog_id) errors.add(:blog_id, "不属于当前用户") end end

注意最里层的TagForm(表单数组里的元素)同样能用context.user做归属校验——这就是"深度上下文"的价值:无需把依赖会话信息的校验逻辑上移到 Command,表单内部即可完成全部数据检查。

🔍 别混淆:附加参数 vs 上下文

两者都能"给表单塞数据",但去向不同:

方式数据去向适用场景
from_params(params, ip: "1.2.3.4")填充表单属性上下文要成为表单字段值
with_context(user: current_user)存入context仅校验/加工逻辑需要读取,不属于表单数据

判断标准很简单:它会出现在表单字段里吗?会 → 用附加参数;不会、只是校验要用 → 用with_context

✅ 上手清单

  • 只需在根表单调用一次with_context,深层嵌套自动继承
  • 传 Hash 时按OpenStruct存储,用context.key方式访问
  • 只传递校验真正需要的最小信息(当前用户、租户 ID、IP 等)
  • 想临时跳过子表单校验时,可搭配valid?(exclude_nested: true)valid?(exclude_arrays: true)选项

结语

with_context是 Rectify Form Object 中不起眼却威力十足的小工具:一行注入、深度共享,让嵌套表单与表单数组里的每一条校验都能从容"看见"当前用户。把它和 Command、Query Object 组合使用,Rails 应用的业务逻辑从此各得其所,代码也更易测试与扩展。

【免费下载链接】rectifyBuild maintainable Rails apps项目地址: https://gitcode.com/gh_mirrors/re/rectify

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询