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不只是给根表单自己用,它会沿着两条线自动向下传播:
- 嵌套表单属性(如
SchoolForm内嵌TeacherForm) - 表单数组属性(如
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),仅供参考