无法使用ruby%x命令在curl中传递数组

时间:2016-05-19 12:28:34

标签: ruby-on-rails ruby curl

您好我通过%x()在ruby应用程序中的curl命令中传递了一组id,但是我无法将这些抛出错误添加为:

JSON_PARSING_ERROR: Unexpected character (d) at position 

数组:@m = ["d_sample_id1","d_sample_id2"]

使用的命令:

%x(curl --header 'Authorization: key=keynotmentioned' --header 'Content-Type: application/json' https://android.googleapis.com/gcm/send -d '{"registration_ids": "#{@m}", "collapse_key": "Turn", "data": { "title": "test", "sound": true,"body": "test", "badge": "1" , "content_available": 1 ,"url": ""}}')

显示json解析错误,你可以帮我解决这个问题吗? 提前完成。

1 个答案:

答案 0 :(得分:2)

首先让我们弄清楚出了什么问题。这是为了简洁而修剪代码的近似值:

ids = ["d_sample_id1","d_sample_id2"]
puts %(curl ... -d '{"registration_ids": "#{ids}"}')

我在这里使用puts %()代替%x(...)来打印字符串而不是执行它。这是输出:

curl ... -d '{"registration_ids": "["d_sample_id1", "d_sample_id2"]"}'

发现问题?它在这里:"["d_...。您已将数组放在双引号内。当JSON解析器看到它认为的第一个双引号时,这就是字符串"的开头。然后它在方括号之后到达下一个双引号,并且认为,"并且这是字符串的结尾。"但下一个字符是字母d,它在字符串后面没有任何意义,因此解析器会抛出错误并将其调用一天。

可以通过删除多余的引号来解决这个问题。但它最多只能是一个创可贴,因为它只会偶然地 。在Ruby中使用字符串插值时,Ruby会在to_s内的表达式上调用#{...}。但是,当您在Ruby字符串数组上调用to_s时,您获得了有效的JSON,这只是偶然的。如果表达式是Hash或Date,该怎么办?字符串插值会让你失望。

但即使你知道你刚刚得到一个字符串数组,插值也会因为第二个原因而失败:你需要构建命令行参数,这需要正确转义。以此为例:

arr = ["I can't even"]
%(curl ... -d '#{arr}')

发现问题?这将尝试执行以下操作:

curl ... -d '["I can't even"]'

发现问题?这次你的单引号不匹配。

多么噩梦!

这引出了两个重要的经验法则:

  1. 除非您喜欢痛苦和痛苦,否则不要使用字符串连接/插值构建JSON。

  2. 使用字符串连接/插值来构建命令行参数时要非常小心,除非您喜欢痛苦和痛苦。

  3. 幸运的是,我们不必担心我们的JSON格式正确或我们的命令行参数被正确转义,因为比我们更聪明的人已经担心这些事情并将解决方案直接放入Ruby&#39标准库,令人愉快的JSON和Shellwords模块。所以:

    require "json"
    require "shellwords"
    
    ids = [ "d_sample_id1", "d_sample_id2" ]
    
    data = {
      registration_ids: ids,
      collapse_key: "Turn",
      data: { 
        title: "test",
        sound: true,
        body: "test",
        badge: "1" ,
        content_available: 1,
        url: ""
      }
    }
    
    json_arg = Shellwords.escape(data.to_json)
    
    %x(curl \
      --header 'Authorization: key=keynotmentioned' \
      --header 'Content-Type: application/json' \
      "https://android.googleapis.com/gcm/send" \
      -d #{json_arg}
    )
    

    作为奖励,能够将我们的数据设置为Ruby Hash使其更具可读性,可维护性和可测试性。