You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails应用JSON Schema动态属性未获权限问题求助

Rails STI + JSONB 属性权限未通过问题排查

使用Rails的STI模式,Product模型包含JSONB类型的dynamic_attributes字段存储不同产品类型的专属属性。编辑Lock类型产品时,提交的:kind和:interface参数提示未获权限,改用permit!可正常更新但存在安全风险。

Lock模型代码

class Lock < Product
  serialize :dynamic_attributes, JsonbSerializers
  store_accessor :dynamic_attributes, :kind, :interface
  validates :kind, presence: true

  def json_schema
    Rails.root.join('app', 'models', 'schemas', 'lock_category.json')
  end
end

JSON Schema定义

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "required": [ "kind" ],
  "properties": {
    "kind": { 
      "type": "string",
      "enum": ["Cable", "Chain", "Folding", "Frame", "Part", "Padlock", "U-Lock", "U-Lock+Cable"]
    },
    "interface": {
      "type": "string",
      "enum": ["Key", "Combination", "Smart"]
    }
  }
}

Products控制器代码

def update
  @product = Product.find(params[:id])
  @product.update!(product_params)
  redirect_to @product
end

private
  
def product_params
  params.require(:product).
  permit(
    :type,
    :vendor,
    :description,
    :cost,
    :msrp,
    dynamic_attributes: [
      :kind,
      :interface
    ]
  )
end

编辑表单代码片段

<% @product[:dynamic_attributes].each do |k,v| %>
  <%= f.label k.to_sym %>  
  <%= f.text_field k.to_sym, :value => v %>
  <br />
<% end %>

PATCH请求日志

Started PATCH "/products/0c092119-601c-4dbb-b05b-3ad5ac638631" for 127.0.0.1 at 2023-03-09 12:41:06 -0600
Processing by ProductsController#update as TURBO_STREAM
  Parameters: {"authenticity_token"=>"[FILTERED]", "product"=>{"vendor"=>"Vendor", "description"=>"First Lock", "cost"=>"37.5", "msrp"=>"74.99", "type"=>"Lock", "kind"=>"U-Lock", "interface"=>"Smart"}, "commit"=>"Update Product", "id"=>"0c092119-601c-4dbb-b05b-3ad5ac638631"}
  Product Load (0.3ms)  SELECT "products".* FROM "products" WHERE "products"."id" = $1 LIMIT $2  [["id", "0c092119-601c-4dbb-b05b-3ad5ac638631"], ["LIMIT", 1]]
  ↳ app/controllers/products_controller.rb:23:in `update'
Unpermitted parameters: :kind, :interface. Context: { controller: ProductsController, action: update, request: #<ActionDispatch::Request:0x00007fbba812f500>, params: {"_method"=>"patch", "authenticity_token"=>"[FILTERED]", "product"=>{"vendor"=>"Vendor", "description"=>"First Lock", "cost"=>"37.5", "msrp"=>"74.99", "type"=>"Lock", "kind"=>"U-Lock", "interface"=>"Smart"}, "commit"=>"Update Product", "controller"=>"products", "action"=>"update", "id"=>"0c092119-601c-4dbb-b05b-3ad5ac638631"} }
  TRANSACTION (0.1ms)  BEGIN
  ↳ app/controllers/products_controller.rb:24:in `update'
  Product Exists? (0.3ms)  SELECT 1 AS one FROM "products" WHERE "products"."vpn" = $1 AND "products"."id" != $2 AND "products"."vendor" = $3 LIMIT $4  [["vpn", "453"], ["id", "0c092119-601c-4dbb-b05b-3ad5ac638631"], ["vendor", "Vendor"], ["LIMIT", 1]]
  ↳ app/controllers/products_controller.rb:24:in `update'
  TRANSACTION (0.1ms)  COMMIT
  ↳ app/controllers/products_controller.rb:24:in `update'
Redirected to http://localhost:3000/products/0c092119-601c-4dbb-b05b-3ad5ac638631
Completed 302 Found in 7ms (ActiveRecord: 0.7ms | Allocations: 5365)

问题原因分析

从请求日志可以明确看到,提交的:kind和:interface参数直接位于product根节点下,而非控制器权限配置中期望的dynamic_attributes嵌套结构。

问题出在表单代码:使用f.text_field k.to_sym生成的input字段name为product[kind],而非product[dynamic_attributes][kind],导致参数提交时未嵌套到目标字段下,触发权限校验失败。

解决方案

方案1:修正表单字段命名

修改表单代码,将动态属性输入字段嵌套到dynamic_attributes命名空间下:

<% @product[:dynamic_attributes].each do |k,v| %>
  <%= f.label "dynamic_attributes[#{k}]" %>  
  <%= f.text_field :"dynamic_attributes[#{k}]", :value => v %>
  <br />
<% end %>

方案2:使用fields_for处理嵌套属性

更规范的写法是用fields_for生成嵌套字段:

<%= f.fields_for :dynamic_attributes do |da_form| %>
  <% @product.dynamic_attributes.each do |k, v| %>
    <%= da_form.label k.to_sym %>
    <%= da_form.text_field k.to_sym, value: v %>
    <br />
  <% end %>
<% end %>

两种方案都能让参数正确嵌套到dynamic_attributes下,匹配控制器的权限配置,同时贴合Model中store_accessor的设计逻辑,避免使用permit!带来的安全风险。

内容的提问来源于stack exchange,提问作者dukehenry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 17:47:08