xdevplatform/twitter-ruby-ads-sdk

400 error when calling `save` on an already-saved line item object

Closed this issue · 1 comments

I created a line item following the code in the quickstart example (https://github.com/twitterdev/twitter-ruby-ads-sdk/blob/master/examples/quick_start.rb). It was successfully created, but after calling save a second time, I got a 400 error:

=> #<TwitterAds::LineItem:0x2166866700 id="by3j">
[27] pry(#<String>)> CLIENT.options[:trace] =true
=> true
[28] pry(#<String>)> line_item.save
I, [2015-10-14T10:49:26.760944 #34286]  INFO -- twitter-ads: Send: PUT https://ads-api-sandbox.twitter.com/0/accounts/gq1013/line_items/by3j {:id=>"by3j", :created_at=>"2015-10-14T14:49:13Z", :updated_at=>"2015-10-14T14:49:13Z", :name=>"my first ad", :campaign_id=>"fbu5", :categories=>"", :charge_by=>"ENGAGEMENT", :include_sentiment=>"POSITIVE_ONLY", :objective=>"TWEET_ENGAGEMENTS", :optimization=>"DEFAULT", :paused=>true, :product_type=>"PROMOTED_TWEETS", :placements=>"ALL_ON_TWITTER", :bid_unit=>"ENGAGEMENT", :bid_amount_local_micro=>10000}
I, [2015-10-14T10:49:26.761003 #34286]  INFO -- twitter-ads: Header: accept-encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
I, [2015-10-14T10:49:26.761026 #34286]  INFO -- twitter-ads: Header: accept: */*
I, [2015-10-14T10:49:26.761045 #34286]  INFO -- twitter-ads: Header: user-agent: twitter-ads version: 0.2.3 platform: ruby 2.1.1 (x86_64-darwin12.0) (OAuth gem v0.4.7)
I, [2015-10-14T10:49:26.761074 #34286]  INFO -- twitter-ads: Header: authorization: OAuth oauth_body_hash="2jmj7l5rSw0yVb%2FvlWAYkK%2FYBwk%3D", oauth_consumer_key="EXCISED", oauth_nonce="D5Zkia5xe1QS6VxjlukcxAoqAYBvgmozdAZro8uWpM", oauth_signature="UA3Id%2FsgqmOSq82BZ%2BqamSQknVc%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1444834166", oauth_token="16320551-VWC5oujzIN4B8aWKjt3etbntPkYHS3C2EOEEDNaTz", oauth_version="1.0"
I, [2015-10-14T10:49:26.949160 #34286]  INFO -- twitter-ads: Status: 400 Bad Request
I, [2015-10-14T10:49:26.949232 #34286]  INFO -- twitter-ads: Header: connection: close
I, [2015-10-14T10:49:26.949257 #34286]  INFO -- twitter-ads: Header: content-disposition: attachment; filename=json.json
I, [2015-10-14T10:49:26.949279 #34286]  INFO -- twitter-ads: Header: content-length: 265
I, [2015-10-14T10:49:26.949298 #34286]  INFO -- twitter-ads: Header: content-type: application/json;charset=utf-8
I, [2015-10-14T10:49:26.949318 #34286]  INFO -- twitter-ads: Header: date: Wed, 14 Oct 2015 14:49:27 GMT
I, [2015-10-14T10:49:26.949338 #34286]  INFO -- twitter-ads: Header: server: tsa_b
I, [2015-10-14T10:49:26.949409 #34286]  INFO -- twitter-ads: Header: set-cookie: guest_id=v1%3A144483416711915357; Domain=.twitter.com; Path=/; Expires=Fri, 13-Oct-2017 14:49:27 UTC
I, [2015-10-14T10:49:26.949430 #34286]  INFO -- twitter-ads: Header: strict-transport-security: max-age=631138519
I, [2015-10-14T10:49:26.949449 #34286]  INFO -- twitter-ads: Header: x-access-level: read-write
I, [2015-10-14T10:49:26.949468 #34286]  INFO -- twitter-ads: Header: x-connection-hash: 1224a019df235ca69c49f728a00a4c3d
I, [2015-10-14T10:49:26.949487 #34286]  INFO -- twitter-ads: Header: x-content-type-options: nosniff
I, [2015-10-14T10:49:26.949506 #34286]  INFO -- twitter-ads: Header: x-frame-options: SAMEORIGIN
I, [2015-10-14T10:49:26.949525 #34286]  INFO -- twitter-ads: Header: x-rate-limit-limit: 300
I, [2015-10-14T10:49:26.949544 #34286]  INFO -- twitter-ads: Header: x-rate-limit-remaining: 299
I, [2015-10-14T10:49:26.949563 #34286]  INFO -- twitter-ads: Header: x-rate-limit-reset: 1444834213
I, [2015-10-14T10:49:26.949581 #34286]  INFO -- twitter-ads: Header: x-response-time: 90
I, [2015-10-14T10:49:26.949600 #34286]  INFO -- twitter-ads: Header: x-runtime: 0.020043
I, [2015-10-14T10:49:26.949619 #34286]  INFO -- twitter-ads: Header: x-transaction: 78670065647039ba
I, [2015-10-14T10:49:26.949638 #34286]  INFO -- twitter-ads: Header: x-xss-protection: 1; mode=block
I, [2015-10-14T10:49:26.949656 #34286]  INFO -- twitter-ads: Body: {"errors":[{"code":"INVALID_PARAMETER","message":"A minimum of 1 items must be provided for categories","parameter":"categories"}],"request":{"params":{"line_item_id":"by3j","name":"my first ad","bid_amount_local_micro":10000,"paused":true,"account_id":"gq1013","optimization":"DEFAULT","include_sentiment":"POSITIVE_ONLY"}}}
TwitterAds::BadRequest: #<TwitterAds::BadRequest:0x2175767560 code=400 details="[{:code=>"INVALID_PARAMETER", :message=>"A minimum of 1 items must be provided for categories", :parameter=>"categories"}]">
from /Users/luke/.rvm/gems/ruby-2.1.1@global/gems/twitter-ads-0.2.3/lib/twitter-ads/request.rb:56:in `perform'

Thanks for reporting @lukeasrodgers.

The Ads API has some quirky logic server-side with regard to unsetting params. For example, passing param= or param=null triggers different types of unset behavior on a given API object. In this specific case, a new param on the line item categories was defaulting to an empty array and the SDK wasn't handling building a request for that correct. It was serializing the empty array to categories= causing the API to reject the invalid request.

I resolved this issue in last week's 0.2.4 release. Please let me know if you run into any other problems.