Rails不允许来自JSON模式的有效负载

huangapple go评论80阅读模式
英文:

Rails not permitting payload from JSON schema

问题

我正在试图弄清楚为什么我的Rails应用程序不允许我的属性,并且已经没有任何想法了。

我在我的数据库中有产品(Product模型),它们有一组适用于所有产品的标准属性。我有一个名为dynamic_attributes的JSONB列,它专门针对不同类型的产品。因此,我目前正在使用STI。

如果我尝试编辑单个记录,我会收到有关未经许可的参数(我试图从编辑表单中更新/补丁的JSON参数)的错误。如果我删除.permit部分,只是允许一切,那么我就不会收到错误,并且一切都会更新,但显然这不是理想的解决方案。

STI的Lock子类

  1. class Lock < Product
  2. serialize :dynamic_attributes, JsonbSerializers
  3. store_accessor :dynamic_attributes, :kind, :interface
  4. validates :kind, presence: true
  5. def json_schema
  6. Rails.root.join('app', 'models', 'schemas', 'lock_category.json')
  7. end
  8. end

它引用了产品类型的以下JSON模式:

  1. {
  2. "$schema": "http://json-schema.org/draft-04/schema#",
  3. "type": "object",
  4. "required": [ "kind" ],
  5. "properties": {
  6. "kind": {
  7. "type": "string",
  8. "enum": ["Cable", "Chain", "Folding", "Frame", "Part", "Padlock", "U-Lock", "U-Lock+Cable"]
  9. },
  10. "interface": {
  11. "type": "string",
  12. "enum": ["Key", "Combination", "Smart"]
  13. }
  14. }
  15. }

产品控制器

  1. def update
  2. @product = Product.find(params[:id])
  3. @product.update!(product_params)
  4. redirect_to @product
  5. end
  6. private
  7. def product_params
  8. params.require(:product).
  9. permit(
  10. :type,
  11. :vendor,
  12. :description,
  13. :cost,
  14. :msrp,
  15. dynamic_attributes: [
  16. :kind,
  17. :interface
  18. ]
  19. )
  20. end
  21. end

编辑表单非常标准,用于更新dynamic_attributes的部分如下:

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

如果我要猜测(在这一点上我只能猜测),我认为问题可能在于从数据库加载信息到编辑字段,然后再次返回之间。

尝试PATCH的日志:

  1. Started PATCH "/products/0c092119-601c-4dbb-b05b-3ad5ac638631" for 127.0.0.1 at 2023-03-09 12:41:06 -0600
  2. Processing by ProductsController#update as TURBO_STREAM
  3. 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"}
  4. Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."id" = $1 LIMIT $2 [["id", "0c092119-601c-4dbb-b05b-3ad5ac638631"], ["LIMIT", 1]]
  5. app/controllers/products_controller.rb:23:in `update'
  6. 未经许可的参数: :kind, :interface。上下文: { 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"} }
  7. TRANSACTION (0.1ms) BEGIN
  8. ↳ app/controllers/products_controller.rb:24:in `update'
  9. 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]]
  10. ↳ app/controllers/products_controller.rb:24:in `update'
  11. TRANSACTION (0.1ms) COMMIT
  12. app/controllers/products_controller.rb:24:in `update'
  13. Redirected to http://localhost:3000/products/0c092119-601c-4dbb-b05b-3ad5ac638631
  14. Completed 302 Found in 7ms (ActiveRecord: 0.7ms | Allocations: 5365)
英文:

I am trying to figure out why my rails app is not permitting my attributes and have run out of ideas.

I have products in my database (model Product) and they have a collection of standard attributes that apply to all products. I have an additional JSONB column called dynamic_attributes that is specific to different types of product. Due to this, I am currently using STI.

If I attempt to edit an individual record, I get an error regarding unpermitted parameters (the JSON parameters I am trying to update/patch from the edit form). If I remove the .permit section and just permit! everything then I get no errors and everything updates but obviously this isn't ideal.

Lock subclass for STI

  1. class Lock &lt; Product
  2. serialize :dynamic_attributes, JsonbSerializers
  3. store_accessor :dynamic_attributes, :kind, :interface
  4. validates :kind, presence: true
  5. def json_schema
  6. Rails.root.join(&#39;app&#39;, &#39;models&#39;, &#39;schemas&#39;, &#39;lock_category.json&#39;)
  7. end
  8. end

which references the following JSON schema for the product type in question:

  1. {
  2. &quot;$schema&quot;: &quot;http://json-schema.org/draft-04/schema#&quot;,
  3. &quot;type&quot;: &quot;object&quot;,
  4. &quot;required&quot;: [ &quot;kind&quot; ],
  5. &quot;properties&quot;: {
  6. &quot;kind&quot;: {
  7. &quot;type&quot;: &quot;string&quot;,
  8. &quot;enum&quot;: [&quot;Cable&quot;, &quot;Chain&quot;, &quot;Folding&quot;, &quot;Frame&quot;, &quot;Part&quot;, &quot;Padlock&quot;, &quot;U-Lock&quot;, &quot;U-Lock+Cable&quot;]
  9. },
  10. &quot;interface&quot;: {
  11. &quot;type&quot;: &quot;string&quot;,
  12. &quot;enum&quot;: [&quot;Key&quot;, &quot;Combination&quot;, &quot;Smart&quot;]
  13. }
  14. }
  15. }

Products Controller

  1. def update
  2. @product = Product.find(params[:id])
  3. @product.update!(product_params)
  4. redirect_to @product
  5. end
  6. private
  7. def product_params
  8. params.require(:product).
  9. permit(
  10. :type,
  11. :vendor,
  12. :description,
  13. :cost,
  14. :msrp,
  15. dynamic_attributes: [
  16. :kind,
  17. :interface
  18. ]
  19. )
  20. end
  21. end

and the edit form is pretty standard with the following section for updating the dynamic_attributes:

  1. &lt;% @product[:dynamic_attributes].each do |k,v| %&gt;
  2. &lt;%= f.label k.to_sym %&gt;
  3. &lt;%= f.text_field k.to_sym, :value =&gt; v %&gt;
  4. &lt;br /&gt;
  5. &lt;% end %&gt;

If I were to guess (all I have left at this point, I think it is probably something between loading the information from the database into the edit field and then back again.

The log from the attempted PATCH:

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

答案1

得分: 2

感谢 @engineersmnky 给出的答案:

"kind" 和 "interface" 不被允许,因为您声明它们应该嵌套在 "dynamic_attributes" 下,但在请求中它们没有嵌套。也许尝试更改如下代码:

  1. f.text_field k.to_sym, to: f.text_field("dynamic_attributes[#{k}]")

所以我根据这个更新了我的代码:

  1. <% @product[:dynamic_attributes].each do |k,v| %>
  2. <%= f.label k.to_sym %>
  3. <%= f.text_field "dynamic_attributes[#{k}]", :value => v %>
  4. <% end %>
英文:

Thanks to @engineersmnky who had the answer:

kind, and interface are not permitted because you are stating that they should be nested under dynamic_attributes but in the request they are not nested. Maybe try changing this

  1. f.text_field k.to_sym to f.text_field &quot;dyanmic_attributes[#{k}]&quot;

So I updated my code accordingly to:

  1. &lt;% @product[:dynamic_attributes].each do |k,v| %&gt;
  2. &lt;%= f.label k.to_sym %&gt;
  3. &lt;%= f.text_field &quot;dynamic_attributes[#{k}]&quot;, :value =&gt; v %&gt;
  4. &lt;% end %&gt;

huangapple
  • 本文由 发表于 2023年3月10日 01:20:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75687998.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定