Rails表单多态字段用Signed Global IDs报错:String类无primary_key方法
解决Rails多态关联中使用Signed Global ID时的
undefined method 'primary_key' for String:Class错误 错误原因
表单提交时,你给commentable属性传递的是Signed Global ID的字符串,但Rails的多态关联属性需要接收的是模型实例。Rails尝试对字符串调用仅模型类才有的primary_key方法,因此抛出该错误。
解决方案
需要把提交的SGID字符串解析为对应的模型实例后,再赋值给commentable属性,具体步骤如下:
1. 修改CommentsController逻辑
class CommentsController < ApplicationController def new # 从路由参数中获取要评论的对象(Post或Photo) @commentable = Post.find_by(id: params[:post_id]) || Photo.find_by(id: params[:photo_id]) @comment = Comment.new end def create @comment = Comment.new(comment_params) # 解析Signed Global ID为模型实例 commentable_sgid = params[:comment][:commentable] @comment.commentable = GlobalID::Locator.locate_signed(commentable_sgid) # 处理SGID解析失败的情况 if @comment.commentable.nil? @comment.errors.add(:commentable, "无效的关联对象") render :new return end if @comment.save redirect_to @comment.commentable, notice: "评论创建成功" else render :new end end private def comment_params # 仅允许评论内容等字段,commentable单独处理 params.require(:comment).permit(:content) end end
2. 确保表单正确传递Signed Global ID
在评论表单中,通过模型实例的to_signed_global_id方法生成合法的SGID,作为隐藏字段传递:
<%# app/views/comments/new.html.erb %> <%= form_with model: @comment do |form| %> <%# 传递关联对象的Signed Global ID %> <%= form.hidden_field :commentable, value: @commentable.to_signed_global_id %> <%= form.label :content %> <%= form.text_area :content %> <%= form.submit "提交评论" %> <% end %>
3. 配置嵌套路由(可选)
为了更合理地传递关联对象的ID,建议配置嵌套路由:
# config/routes.rb resources :posts do resources :comments, only: [:new, :create] end resources :photos do resources :comments, only: [:new, :create] end
关键说明
GlobalID::Locator.locate_signed会自动验证SGID的合法性(防止篡改、过期),验证通过则返回对应模型实例,失败则返回nil。- Rails 5及以上版本默认支持Signed Global ID功能,无需额外配置。
内容的提问来源于stack exchange,提问作者user29559775
相关产品推荐
相关产品推荐

