主要观点:在使用 Ruby on Rails 构建面向 CRUD 的 Web 应用时,大部分内容较简单,但处理表单中的多态关联是个缺口,可借助全局 ID来解决。以创建包含多态content
(可为Article
或Video
)的Post
应用为例,通过 Rails CLI 生成相关资源后,发现生成的_form
部分表单并非生产就绪,对于多态关联不能使用常规的form.collection_select
,而应使用全局 ID。
关键信息:
- 通过
bin/rails generate scaffold Post title:string! content:belongs_to{polymorphic}
生成相关迁移文件和模型文件。 - 原
_form
部分的form.text_field :content_id
方式不可行,因多态关联无单个Content
模型。 - 利用全局 ID 构建单
<select>
并分组选项的表单字段,如form.select(:content_gid, grouped_options_for_select([['Articles', Article.order(:title).map { |it| [it.title, it.to_gid.to_s] }], ['Videos', Video.order(:title).map { |it| [it.title, it.to_gid.to_s] }]]))
。 - 为模型添加
content_gid
和content_gid=
访问器,前者获取关联content
的全局 ID,后者通过全局 ID 设置关联。 - 可添加初始器
config/initializers/polymorphic_belongs_to_gid.rb
为带有多态belongs_to
关联的所有 ActiveRecord 模型定义*_gid
访问器。
重要细节:
- 全局 ID 是应用范围内唯一标识模型实例的 URI,如
gid://YourApp/Some::Model/id
,可编码类名和 ID 提供多态关联所需信息。 - 后续更新指出使用签名全局 ID可防止客户端篡改,需修改相关方法和表单代码,如将
.to_gid
改为.to_sgid
,GlobalID::Locator.locate
改为GlobalID::Locator.locate_signed
,并创建Contentable
模型关注点用于定义和实现多态content
关联所需的接口,如Article
模型中的public_name
和public_order
方法。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。