Rails中的WhiteListing参数5

时间:2018-01-03 01:54:01

标签: ruby-on-rails postgresql jsonb

如果从GUI传递数组/哈希,这与白名单参数有关。

以下是我想要的白名单。

  1. 但是在服务器端看到一个错误,说明未经许可的参数。
  2. 注意:Orderplaced字段的类型为JSONB

    private
     def order_params
     #params.require(:order).permit(:ordertype, :orderplaced => [:itemname => [], :quantity => [], :unitprice => [], :tax => [], :discount => [], :itemtotalprice => [] ])
     params.require(:order).permit(:ordertype, :orderplaced => [ { itemname: [], quantity: [], unitprice: [], tax: [], discount: [], itemtotalprice: [] }])
    #not working with either of the above statements.
     end
    end
    

    服务器端错误未允许的参数

    Started POST "/orders" for 127.0.0.1 at 2018-01-03 20:00:23 +0530
    Processing by OrdersController#create as HTML
      Parameters: {"order"=>{"ordertype"=>"Home Delivery", "totalprice"=>"30", "paymentmethod"=>"Cash", "orderplaced"=>{":itemname"=>{"0"=>"Potatoe"}, ":quantity"=>{"0"=>"1"}, ":unitprice"=>{"0"=>"10"}, ":tax"=>{"0"=>"0"}, ":discount"=>{"0"=>"0"}, ":itemtotalprice"=>{"0"=>"10"}}}, "utf8"=>"Γ£ô", "authenticity_token"=>"1etU+M03uuTl8wcGij1+qEaSFcp/UvgBu3g/xBh0Hmexm4rA1vtCc1mkIWFsw8XcfC2sz2e9TBSmSBZNA9KiNA==", "commit"=>"Create Order"}
    Unpermitted parameters: ::itemname, ::quantity, ::unitprice, ::tax, ::discount, ::itemtotalprice
      Customer Load (0.0ms)  SELECT  "customers".* FROM "customers" ORDER BY "customers"."id" ASC LIMIT $1  [["LIMIT", 1]]
       (0.0ms)  BEGIN
      SQL (4.0ms)  INSERT INTO "orders" ("ordertype", "orderplaced", "totalprice", "paymentmethod", "created_at", "updated_at", "customer_id") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["ordertype", "Home Delivery"], ["orderplaced", "{}"], ["totalprice", 30.0], ["paymentmethod", "Cash"], ["created_at", "2018-01-03 14:30:23.393041"], ["updated_at", "2018-01-03 14:30:23.393041"], ["customer_id", 1]]
       (8.0ms)  COMMIT
    
    1. 如果我使用params.require(:order).permit!,那么我也只看到第一个值索引,即array [0]通过params传递并保存到DB。那我们怎样才能得到其余的。
    2. GUI: Here is the UI i am using to pass the values

3 个答案:

答案 0 :(得分:0)

您的代码存在许多问题。首先,您的白名单语法不正确。它应该更像是:

params.require(:order).permit(:ordertype, :totalprice, :paymentmethod, {orderplaced: {":itemname": ["0"], ":quantity": ["0"], ":unitprice": ["0"], ":tax": ["0"], ":discount": ["0"], ":itemtotalprice": ["0"]}})

在控制台中,这将为您提供:

> params.require(:order).permit(:ordertype, :totalprice, :paymentmethod, {orderplaced: {":itemname": ["0"], ":quantity": ["0"], ":unitprice": ["0"], ":tax": ["0"], ":discount": ["0"], ":itemtotalprice": ["0"]}})
 => {"ordertype"=>"Home Delivery", "totalprice"=>"30", "paymentmethod"=>"Cash", "orderplaced"=>{":itemname"=>{"0"=>"Potatoe"}, ":quantity"=>{"0"=>"1"}, ":unitprice"=>{"0"=>"10"}, ":tax"=>{"0"=>"0"}, ":discount"=>{"0"=>"0"}, ":itemtotalprice"=>{"0"=>"10"}}}

这还有两个问题:

  1. 您的orderplaced值仍然使用密钥"0"(例如":itemname"=>{"0"=>"Potatoe"})和
  2. 嵌入哈希中
  3. 您的orderplaced个密钥在开头都有:(例如":itemname"
  4. (由于您将orderplaced存储在JSONB列中并且这是有效的JSON,您可以忽略这些问题。但是,现在清理它将为您或您的同事带来未来的心痛。)

    您可以通过执行以下操作来解决此问题:

    def orderplaced_params
      order_params[:orderplaced].each_with_object({}) do |(k,v), returning|
        returning[k.gsub(":","")] = v["0"]
      end
    end
    

    再次在控制台中,它会给你:

    > orderplaced_params
     => {"itemname"=>"Potatoe", "quantity"=>"1", "unitprice"=>"10", "tax"=>"0", "discount"=>"0", "itemtotalprice"=>"10"}
    

    现在,您需要重新组合固定的order_params。类似的东西:

    def fixed_order_params
      order_params.slice(:ordertype, :totalprice, :paymentmethod).merge!(orderplaced: orderplaced_params)
    end
    

    哪个会给你:

    > fixed_order_params
     => {"ordertype"=>"Home Delivery", "totalprice"=>"30", "paymentmethod"=>"Cash", "orderplaced"=>{"itemname"=>"Potatoe", "quantity"=>"1", "unitprice"=>"10", "tax"=>"0", "discount"=>"0", "itemtotalprice"=>"10"}}
    

    我有一种感觉,这不是故事的结局。根据你的用户界面(你还在发布图片!BOO!),我原本期望orderplaced是一个哈希数组。类似的东西:

    Parameters: {
      "order"=>{
        "ordertype"=>"Home Delivery", 
        "totalprice"=>"30", 
        "paymentmethod"=>"Cash", 
        "orderplaced"=>[
          {
            ":itemname"=>{"0"=>"Potatoe"}, 
            ":quantity"=>{"0"=>"1"}, 
            ":unitprice"=>{"0"=>"10"}, 
            ":tax"=>{"0"=>"0"}, 
            ":discount"=>{"0"=>"0"}, 
            ":itemtotalprice"=>{"0"=>"10"}
          },
          {
            ":itemname"=>{"0"=>"Television"}, 
            ":quantity"=>{"0"=>"1"}, 
            ":unitprice"=>{"0"=>"10"}, 
            ":tax"=>{"0"=>"0"}, 
            ":discount"=>{"0"=>"0"}, 
            ":itemtotalprice"=>{"0"=>"10"}
          },
          {
            ":itemname"=>{"0"=>"Cable"}, 
            ":quantity"=>{"0"=>"1"}, 
            ":unitprice"=>{"0"=>"10"}, 
            ":tax"=>{"0"=>"0"}, 
            ":discount"=>{"0"=>"0"}, 
            ":itemtotalprice"=>{"0"=>"10"}
          }
        ]
      }, 
      "utf8"=>"Γ£ô", 
      "authenticity_token"=>"1etU+M03uuTl8wcGij1+qEaSFcp/UvgBu3g/xBh0Hmexm4rA1vtCc1mkIWFsw8XcfC2sz2e9TBSmSBZNA9KiNA==",
      "commit"=>"Create Order"
    }
    

    (我假设您希望捕获图片中显示的每一行,作为orderplaced JSONB列的一部分。)

    在这种情况下,orderplaced_pa​​rams需要看起来更像:

    def orderplaced_params
      order_params[:orderplaced].map do |order_line_item|
        order_line_item.each_with_object({}) do |(k,v), hsh|
          hsh[k.gsub(":","")] = v["0"]
        end
      end
    end
    

    这会给你:

    fixed_order_params
     => {"ordertype"=>"Home Delivery", "totalprice"=>"30", "paymentmethod"=>"Cash", "orderplaced"=>[{"itemname"=>"Potatoe", "quantity"=>"1", "unitprice"=>"10", "tax"=>"0", "discount"=>"0", "itemtotalprice"=>"10"}, {"itemname"=>"Television", "quantity"=>"1", "unitprice"=>"10", "tax"=>"0", "discount"=>"0", "itemtotalprice"=>"10"}, {"itemname"=>"Cable", "quantity"=>"1", "unitprice"=>"10", "tax"=>"0", "discount"=>"0", "itemtotalprice"=>"10"}]} 
    

    有几点需要注意:

    • 这是“马铃薯”,而不是“Potatoe”。
    • 您应该研究ruby style guide来格式化代码。变量通常会被强调,例如:order_placed而不是orderplaced
    • 如果我对order_placed的哈希数组是正确的,那么你需要修复你的前端来传递数组而不是哈希。
    • 您应该修正前端,以便order_placed不会在:前加上discount密钥(例如,:discount,而不是order_placed)。
    • 您应修复前端,以便'discount'=>'0'元素不会嵌入哈希值(例如,':discount'=>{'0'=>'0'},而不是order_placed_params

    最后两个会为您节省fixed_order_paramsorder_params所有商家的费用,并允许您返回仅使用NoMethodError (undefined method `each_with_object' for #<ActionController::Parameters:0xc17f808>):

    关注

    要避免:

    ActionController::Parameters

    尝试使用hash

    to_h转换为order_params[:orderplaced].to_h.each_with_object({}) do |(k,v), returning| returning[k.gsub(":","")] = v["0"] end
    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.support.v4.content.LocalBroadcastManager;
    
    import java.util.Arrays;
    
    
    public class ClientUpdater extends Thread {
        ClientCommunication cComm;              //this is my class which manages the Server-Client-Communication
        Intent BroadcastIntentUpdate;           //Intent for the LocalBroadcast
        Context cntxt;                          //stores the context passed in the constructor
        GlobalClass Obj1;                       //Instance of my Singleton
    
        public ClientUpdater(ClientCommunication cComm, Context context) {
            this.cComm = cComm;
            this.cntxt = context;
            BroadcastIntentUpdate = new Intent("update");
        }
    
        public void run(){
            while(true){
    
                String vomS1 = cComm.sendData("updateChat" + "~" + "$empty$");      //sends an update request to the server an receives the current chat-state
                if(!vomS1.equalsIgnoreCase("timeout")){
    
                    Obj1 = GlobalClass.getInstance();
                    String[] update = GlobalClass.decode(vomS1, ";");               //decodes the receives message                  
                    String[] altchat = Obj1.getChat();                              //loads the stored chat protocoll from singleton
    
    
                    if(!Arrays.equals(update, altchat)){                            //if the received message has new data...
    
                        BroadcastIntentUpdate.putExtra("message", update);
                        //for ".getInstance(cntxt)" the current Context is always needed right?
                        LocalBroadcastManager.getInstance(cntxt).sendBroadcast(BroadcastIntentUpdate);          //...it's sent to the activity
                        Obj1.setChat(update);                                                                                           //...and stored in the singleton
                    }
                }    
    
    
                try {
                    sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
    }
    

答案 1 :(得分:0)

非常感谢您的回复。

在进行上述更改后(前端代码尚未修复),我看到一个问题未定义方法each_with_object' for #<ActionController::Parameters:0xc17f808> in orderplaced_pa​​rams`方法。

控制器代码:

class OrdersController < ApplicationController

    def new
        @order=Order.new
    end

    def create
        @order=Order.new(fixed_order_params)
        @order.save
    end

    private
        def order_params
            params.require(:order).permit(:ordertype, :totalprice, :paymentmethod, {orderplaced: {":itemname": ["0"], ":quantity": ["0"], ":unitprice": ["0"], ":tax": ["0"], ":discount": ["0"], ":itemtotalprice": ["0"]}})
        end


        def orderplaced_params
            order_params[:orderplaced].each_with_object({}) do |(k,v), returning|
            returning[k.gsub(":","")] = v["0"]
             end
        end

        def fixed_order_params
            order_params.slice(:ordertype, :totalprice, :paymentmethod).merge!(orderplaced: orderplaced_params)
        end

    end

服务器端错误:

Started POST "/orders" for 127.0.0.1 at 2018-01-04 19:21:44 +0530
Processing by OrdersController#create as HTML
  Parameters: {"order"=>{"ordertype"=>"Home Deivery", "totalprice"=>"25", "paymentmethod"=>"Online", "orderplaced"=>{":quantity"=>{"0"=>"2"}, ":unitprice"=>{"0"=>"10"}, ":tax"=>{"0"=>"0"}, ":discount"=>{"0"=>"0"}, ":itemtotalprice"=>{"0"=>"20"}}}, "utf8"=>"Γ£ô", "authenticity_token"=>"e2RyLPkDVmCdxNgSzmK/Ov4dTJmCS1ZiM6G3T4u+8TflUd2UCOwnDU1/usslNQiZSGJdI3hNym14wehV9ClHfA==", "itemname"=>"Battery", "commit"=>"Create Order"}
Completed 500 Internal Server Error in 12ms (ActiveRecord: 0.0ms)



NoMethodError (undefined method `each_with_object' for #<ActionController::Parameters:0xc17f808>):

app/controllers/orders_controller.rb:25:in `orderplaced_params'
app/controllers/orders_controller.rb:31:in `fixed_order_params'
app/controllers/orders_controller.rb:10:in `create'

一行的前端代码:(通过增加索引值使用Java Script添加其余行)

<tr>
            <td><input id="order[orderplaced][:itemname][0]" name="order[orderplaced][:itemname][0]" type="text" /></td>
            <td><input id="order[orders_attributes][0][quantity]" name="order[orderplaced][:quantity][0]" type="text" /></td>
            <td><input id="order[orders_attributes][0][unitprice]" name="order[orderplaced][:unitprice][0]" type="text" /></td>
            <td><input id="order[orders_attributes][0][tax]" name="order[orderplaced][:tax][0]" type="text" /></td>
            <td><input id="order[orders_attributes][0][discount]" name="order[orderplaced][:discount][0]" type="text" /></td>
            <td><input id="order[orders_attributes][0][itemtotalprice]" name="order[orderplaced][:itemtotalprice][0]" type="text" /></td>
        </tr>

你的猜测是正确的!我希望将orderplaced存储在数据库中,以便我可以提取所需的Key及其值来显示。

哪种方式可以更容易地存储数据。

你出现的东西:

Parameters: {
  "order"=>{
    "ordertype"=>"Home Delivery", 
    "totalprice"=>"30", 
    "paymentmethod"=>"Cash", 
    "orderplaced"=>[
      {
        ":itemname"=>{"0"=>"Potatoe"}, 
        ":quantity"=>{"0"=>"1"}, 
        ":unitprice"=>{"0"=>"10"}, 
        ":tax"=>{"0"=>"0"}, 
        ":discount"=>{"0"=>"0"}, 
        ":itemtotalprice"=>{"0"=>"10"}
      },
      {
        ":itemname"=>{"0"=>"Television"}, 
        ":quantity"=>{"0"=>"1"}, 
        ":unitprice"=>{"0"=>"10"}, 
        ":tax"=>{"0"=>"0"}, 
        ":discount"=>{"0"=>"0"}, 
        ":itemtotalprice"=>{"0"=>"10"}
      },
      {
        ":itemname"=>{"0"=>"Cable"}, 
        ":quantity"=>{"0"=>"1"}, 
        ":unitprice"=>{"0"=>"10"}, 
        ":tax"=>{"0"=>"0"}, 
        ":discount"=>{"0"=>"0"}, 
        ":itemtotalprice"=>{"0"=>"10"}
      }
    ]
  }, 
  "utf8"=>"Γ£ô", 
  "authenticity_token"=>"1etU+M03uuTl8wcGij1+qEaSFcp/UvgBu3g/xBh0Hmexm4rA1vtCc1mkIWFsw8XcfC2sz2e9TBSmSBZNA9KiNA==",
  "commit"=>"Create Order"
}

或者这样

Parameters: {
  "order"=>{
    "ordertype"=>"Home Delivery", 
    "totalprice"=>"30", 
    "paymentmethod"=>"Cash", 
    "orderplaced"=>[
      {
        ":itemname"=>{"0"=>"Potatoe","1"=>"Television","2"=>"Cable"}, 
        ":quantity"=>{"0"=>"1","1"=>"1","2"=>"1"}, 
        ":unitprice"=>{"0"=>"10","1"=>"10","2"=>"10"}, 
        ":tax"=>{"0"=>"0","1"=>"0","2"=>"0"}, 
        ":discount"=>{"0"=>"0","1"=>"0","2"=>"0"}, 
        ":itemtotalprice"=>{"0"=>"10","1"=>"10","2"=>"10"}
      }
    ]
  }, 
  "utf8"=>"Γ£ô", 
  "authenticity_token"=>"1etU+M03uuTl8wcGij1+qEaSFcp/UvgBu3g/xBh0Hmexm4rA1vtCc1mkIWFsw8XcfC2sz2e9TBSmSBZNA9KiNA==",
  "commit"=>"Create Order"
}

答案 2 :(得分:0)

NoMethodError (undefined method []'为nil:NilClass):`

作为初学者,我很难理解最新情况。

我明白这是一个数组问题。但不确定我哪里出错了。

def orderplaced_params
          order_params[:orderplaced].to_h.map do |order_line_item|
            order_line_item.each_with_object({}) do |(k,v), hsh|
              hsh[k.gsub(":","")] = v["0"]
            end
          end
        end