facebook_ads 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61b7ae96792b4405ed2bffbe93924ab38f8df935
4
- data.tar.gz: 453fe5ce1681754ceea78981ca341404352e72ac
3
+ metadata.gz: e6da1d5a4ec51406066404c86c95a51e413617c8
4
+ data.tar.gz: 8520c0ea1111ea0dd115e819643ac1e10cf6922f
5
5
  SHA512:
6
- metadata.gz: 11b7686efbfd515073db8feaecd384ddc8a3e51fbf15ce9b000775fb77654d5aa8a2ca0456b98d7586fe702204bff0e5289646b726d8ae4b01783bbe7e1a80dd
7
- data.tar.gz: a64588d63ce45b8bef1ebd064d6ec2acb263b030a3426c5a9e6c06b4fc82cafefe847600e62834b8357844229437c9ecfb45abafa4e3a5dc2f8fa9ba5bc94af7
6
+ metadata.gz: ce833767545b4d0e32008e02aab0e3c5e94091a5adc3c08fea5e96b74e2e73528699f503208c31fc267194672ad1d6ef24856445bd5c337c7b261cdbbc897fe0
7
+ data.tar.gz: d773c3fd49a912fde691380c36af876e704a2a445cd924d76d933ad2ccaafbf8a2cda2cc36959329a2fcc1b171cd9e8b65273639d06686129104f76032b6d8e5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- facebook_ads (0.1.8)
4
+ facebook_ads (0.1.9)
5
5
  hashie (~> 3.4)
6
6
  rest-client (>= 1.6)
7
7
 
data/facebook_ads.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # To release a new version:
2
2
  # gem build facebook_ads.gemspec
3
- # gem push facebook_ads-0.1.8.gem
3
+ # gem push facebook_ads-0.1.9.gem
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'facebook_ads'
6
- s.version = '0.1.8'
6
+ s.version = '0.1.9'
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.licenses = ['MIT']
9
9
  s.authors = ['Chris Estreich']
@@ -27,8 +27,9 @@ module FacebookAds
27
27
  def create_ad_campaign(name:, objective:, status: 'ACTIVE')
28
28
  raise Exception, "Objective must be one of: #{AdCampaign::OBJECTIVES.to_sentence}" unless AdCampaign::OBJECTIVES.include?(objective)
29
29
  raise Exception, "Status must be one of: #{AdCampaign::STATUSES.to_sentence}" unless AdCampaign::STATUSES.include?(status)
30
- campaign = AdCampaign.post("/#{id}/campaigns", query: { name: name, objective: objective, status: status }, objectify: true)
31
- AdCampaign.find(campaign.id)
30
+ query = { name: name, objective: objective, status: status }
31
+ result = AdCampaign.post("/#{id}/campaigns", query: query)
32
+ AdCampaign.find(result['id'])
32
33
  end
33
34
 
34
35
  # has_many ad_images
@@ -47,7 +48,7 @@ module FacebookAds
47
48
  [name, File.open(path)]
48
49
  end.to_h
49
50
 
50
- response = AdImage.post("/#{id}/adimages", query: files, objectify: false)
51
+ response = AdImage.post("/#{id}/adimages", query: files)
51
52
  files.values.each { |file| File.delete(file.path) }
52
53
  !response['images'].nil? ? ad_images(hashes: response['images'].map { |_key, hash| hash['hash'] }) : []
53
54
  end
@@ -105,8 +106,8 @@ module FacebookAds
105
106
 
106
107
  raise Exception, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.to_sentence}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
107
108
  query = AdCreative.carousel(creative)
108
- creative = AdCreative.post("/#{id}/adcreatives", query: query, objectify: true) # Returns an AdCreative instance.
109
- AdCreative.find(creative.id)
109
+ result = AdCreative.post("/#{id}/adcreatives", query: query)
110
+ AdCreative.find(result['id'])
110
111
  end
111
112
 
112
113
  def create_image_ad_creative(creative)
@@ -118,8 +119,8 @@ module FacebookAds
118
119
 
119
120
  raise Exception, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.to_sentence}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
120
121
  query = AdCreative.photo(creative)
121
- creative = AdCreative.post("/#{id}/adcreatives", query: query, objectify: true) # Returns an AdCreative instance.
122
- AdCreative.find(creative.id)
122
+ result = AdCreative.post("/#{id}/adcreatives", query: query)
123
+ AdCreative.find(result['id'])
123
124
  end
124
125
 
125
126
  def download(url)
@@ -16,7 +16,9 @@ module FacebookAds
16
16
  share_with_object_id: account_id,
17
17
  share_with_object_type: 'Account'
18
18
  }
19
- AdAccount.post("/#{id}/share_with_objects", query: query, objectify: false)
19
+ result = AdAccount.post("/#{id}/share_with_objects", query: query)
20
+ # result['success']
21
+ result # No idea what this response looks like.
20
22
  end
21
23
  end
22
24
  end
@@ -40,8 +40,8 @@ module FacebookAds
40
40
  status: status,
41
41
  is_autobid: is_autobid
42
42
  }
43
- ad_set = AdSet.post("/act_#{account_id}/adsets", query: query, objectify: true) # Returns an AdSet instance.
44
- AdSet.find(ad_set.id)
43
+ result = AdSet.post("/act_#{account_id}/adsets", query: query)
44
+ AdSet.find(result['id'])
45
45
  end
46
46
 
47
47
  # has_many ad_insights
@@ -0,0 +1,5 @@
1
+ module FacebookAds
2
+ class AdException < StandardError
3
+ attr_accessor :code, :title, :message
4
+ end
5
+ end
@@ -17,8 +17,9 @@ module FacebookAds
17
17
  end
18
18
 
19
19
  def create(name:)
20
- catalog = post("/#{FacebookAds.business_id}/product_catalogs", query: { name: name }, objectify: true)
21
- find(catalog.id)
20
+ query = { name: name }
21
+ result = post("/#{FacebookAds.business_id}/product_catalogs", query: query)
22
+ find(result['id'])
22
23
  end
23
24
  end
24
25
 
@@ -30,8 +31,9 @@ module FacebookAds
30
31
 
31
32
  # catalog.create_ad_product_feed(name: 'Test', schedule: { url: 'https://tophatter.com/admin/ad_automation/ad_product_feeds/1.csv', interval: 'HOURLY' })
32
33
  def create_ad_product_feed(name:, schedule:)
33
- feed = AdProductCatalog.post("/#{id}/product_feeds", query: { name: name, schedule: schedule }, objectify: true)
34
- AdProductFeed.find(feed.id)
34
+ query = { name: name, schedule: schedule }
35
+ result = AdProductCatalog.post("/#{id}/product_feeds", query: query)
36
+ AdProductFeed.find(result['id'])
35
37
  end
36
38
 
37
39
  # has_many product_groups
@@ -53,8 +55,8 @@ module FacebookAds
53
55
  end
54
56
 
55
57
  def create_ad_product(data)
56
- product = AdProductCatalog.post("/#{id}/products", query: data, objectify: true)
57
- AdProduct.find(product.id)
58
+ result = AdProductCatalog.post("/#{id}/products", query: data)
59
+ AdProduct.find(result['id'])
58
60
  end
59
61
  end
60
62
  end
@@ -2,7 +2,35 @@ module FacebookAds
2
2
  # An ad set belongs to a campaign and has many ads.
3
3
  # https://developers.facebook.com/docs/marketing-api/reference/ad-campaign
4
4
  class AdSet < Base
5
- FIELDS = %w(id account_id campaign_id adlabels adset_schedule bid_amount bid_info billing_event configured_status created_time creative_sequence effective_status end_time frequency_cap frequency_cap_reset_period frequency_control_specs is_autobid lifetime_frequency_cap lifetime_imps name optimization_goal promoted_object rf_prediction_id rtb_flag start_time targeting updated_time use_new_app_click pacing_type budget_remaining daily_budget lifetime_budget).freeze
5
+ # Full set of fields:
6
+ # FIELDS = %w(
7
+ # id account_id adlabels adset_schedule attribution_window_days
8
+ # bid_amount bid_info billing_event budget_remaining
9
+ # campaign campaign_id configured_status created_time
10
+ # creative_sequence daily_budget effective_status end_time
11
+ # frequency_cap frequency_cap_reset_period
12
+ # frequency_control_specs instagram_actor_id
13
+ # is_autobid is_average_price_pacing lifetime_budget
14
+ # lifetime_frequency_cap lifetime_imps name optimization_goal
15
+ # pacing_type promoted_object recommendations
16
+ # recurring_budget_semantics rf_prediction_id rtb_flag
17
+ # start_time status targeting time_based_ad_rotation_id_blocks
18
+ # time_based_ad_rotation_intervals updated_time
19
+ # use_new_app_click
20
+ # ).freeze
21
+
22
+ # Fields we might actually care about:
23
+ FIELDS = %w(
24
+ id account_id campaign_id
25
+ name
26
+ status configured_status effective_status
27
+ bid_amount billing_event optimization_goal pacing_type
28
+ daily_budget budget_remaining lifetime_budget
29
+ promoted_object
30
+ targeting
31
+ created_time updated_time
32
+ ).freeze
33
+
6
34
  STATUSES = %w(ACTIVE PAUSED DELETED PENDING_REVIEW DISAPPROVED PREAPPROVED PENDING_BILLING_INFO CAMPAIGN_PAUSED ARCHIVED ADSET_PAUSED).freeze
7
35
  BILLING_EVENTS = %w(APP_INSTALLS IMPRESSIONS).freeze
8
36
  OPTIMIZATION_GOALS = %w(APP_INSTALLS OFFSITE_CONVERSIONS).freeze
@@ -26,8 +54,9 @@ module FacebookAds
26
54
  end
27
55
 
28
56
  def create_ad(name:, creative_id:)
29
- ad = Ad.post("/act_#{account_id}/ads", query: { name: name, adset_id: id, creative: { creative_id: creative_id }.to_json }, objectify: true) # Returns an Ad instance.
30
- Ad.find(ad.id)
57
+ query = { name: name, adset_id: id, creative: { creative_id: creative_id }.to_json }
58
+ result = Ad.post("/act_#{account_id}/ads", query: query)
59
+ Ad.find(result['id'])
31
60
  end
32
61
  end
33
62
  end
@@ -7,7 +7,7 @@ module FacebookAds
7
7
  end
8
8
 
9
9
  def get(path, query: {}, objectify:)
10
- query = pack(query, objectify) # Adds access token, fields, etc.
10
+ query = pack(query, objectify: objectify) # Adds access token, fields, etc.
11
11
  uri = "#{FacebookAds.base_uri}#{path}?" + build_nested_query(query)
12
12
  FacebookAds.logger.debug "GET #{uri}"
13
13
  response = begin
@@ -18,8 +18,8 @@ module FacebookAds
18
18
  unpack(response, objectify: objectify)
19
19
  end
20
20
 
21
- def post(path, query: {}, objectify:)
22
- query = pack(query, objectify)
21
+ def post(path, query: {})
22
+ query = pack(query, objectify: false)
23
23
  uri = "#{FacebookAds.base_uri}#{path}"
24
24
  FacebookAds.logger.debug "POST #{uri} #{query}"
25
25
  response = begin
@@ -27,11 +27,11 @@ module FacebookAds
27
27
  rescue RestClient::Exception => e
28
28
  exception(:post, path, e)
29
29
  end
30
- unpack(response, objectify: objectify)
30
+ unpack(response, objectify: false)
31
31
  end
32
32
 
33
33
  def delete(path, query: {})
34
- query = pack(query, false)
34
+ query = pack(query, objectify: false)
35
35
  uri = "#{FacebookAds.base_uri}#{path}?" + build_nested_query(query)
36
36
  FacebookAds.logger.debug "DELETE #{uri}"
37
37
  response = begin
@@ -81,7 +81,7 @@ module FacebookAds
81
81
  object
82
82
  end
83
83
 
84
- def pack(hash, objectify)
84
+ def pack(hash, objectify:)
85
85
  hash = hash.merge(access_token: FacebookAds.access_token)
86
86
  hash = hash.merge(fields: self::FIELDS.join(',')) if objectify
87
87
  hash.delete_if { |_k, v| v.nil? }
@@ -129,21 +129,33 @@ module FacebookAds
129
129
  end
130
130
  end
131
131
 
132
- def exception(verb, path, e)
133
- if e.response.is_a?(String)
132
+ def exception(verb, path, exception)
133
+ FacebookAds.logger.error exception.response
134
+ response = exception.response
135
+
136
+ message = if response.is_a?(String)
134
137
  begin
135
- hash = JSON.parse(e.response)
136
- error = hash['error']
137
- message = error.nil? ? hash.inspect : "#{error['type']} code=#{error['code']} message=#{error['message']}"
138
+ if (error = JSON.parse(response)['error']).nil?
139
+ response
140
+ else
141
+ if error['error_subcode'].nil? ||
142
+ error['error_user_title'].nil? ||
143
+ error['error_user_msg'].nil?
144
+ "#{error['type']} / #{error['code']}: #{error['message']}"
145
+ else
146
+ exception = AdException.new(code: error['error_subcode'], title: error['error_user_title'], message: error['error_user_msg'])
147
+ "#{error['error_subcode']} / #{error['error_user_title']}: #{error['error_user_msg']}"
148
+ end
149
+ end
138
150
  rescue JSON::ParserError
139
- message = e.response.first(100)
151
+ response
140
152
  end
141
153
  else
142
- message = e.response.inspect
154
+ response.inspect
143
155
  end
144
156
 
145
- FacebookAds.logger.error "#{verb.upcase} #{path} [#{e.message}] #{message}"
146
- raise e
157
+ FacebookAds.logger.error "#{verb.upcase} #{path} #{message}"
158
+ raise exception
147
159
  end
148
160
  end
149
161
 
@@ -157,7 +169,7 @@ module FacebookAds
157
169
 
158
170
  def update(data)
159
171
  return false if data.nil?
160
- response = self.class.post("/#{id}", query: data, objectify: false)
172
+ response = self.class.post("/#{id}", query: data)
161
173
  response['success']
162
174
  end
163
175
 
data/test/ad_set_test.rb CHANGED
@@ -2,10 +2,47 @@ require 'test_helper'
2
2
 
3
3
  # rake test TEST=test/ad_set_test.rb
4
4
  class AdSetTest < BaseTest
5
+ def test_create
6
+ vcr do
7
+ ad_campaign = FacebookAds::AdCampaign.find('6069436026057')
8
+ ad_set = ad_campaign.create_ad_set(
9
+ name: 'Test',
10
+ promoted_object: {
11
+ pixel_id: '1472889202927380',
12
+ custom_event_type: 'PURCHASE'
13
+ },
14
+ targeting: {
15
+ age_max: 65,
16
+ age_min: 18,
17
+ app_install_state: 'not_installed',
18
+ excluded_custom_audiences: [{ "name"=>"All-Users-2016-07-28", "id"=>"6068994792257" }],
19
+ genders: [2],
20
+ geo_locations: { countries: %w(US), location_types: %w(home recent) },
21
+ locales: [24, 6],
22
+ publisher_platforms: %w(facebook instagram audience_network),
23
+ device_platforms: %w(desktop),
24
+ facebook_positions: %w(feed right_hand_column)
25
+ },
26
+ daily_budget: 1000,
27
+ optimization_goal: 'OFFSITE_CONVERSIONS'
28
+ )
29
+ assert_equal '6081945233457', ad_set.id
30
+ assert_equal '1000', ad_set.daily_budget
31
+ assert_equal 'OFFSITE_CONVERSIONS', ad_set.optimization_goal
32
+ end
33
+ end
34
+
5
35
  def test_update
6
36
  vcr do
7
37
  ad_set = FacebookAds::AdSet.find('6078462927057')
8
38
  assert ad_set.update(daily_budget: 149900)
9
39
  end
10
40
  end
41
+
42
+ def test_destroy
43
+ vcr do
44
+ ad_set = FacebookAds::AdSet.find('6081945233457')
45
+ assert ad_set.destroy
46
+ end
47
+ end
11
48
  end
@@ -0,0 +1,189 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/v2.8/6069436026057?access_token=TEST_ACCESS_TOKEN&fields=id,account_id,buying_type,can_use_spend_cap,configured_status,created_time,effective_status,name,objective,start_time,stop_time,updated_time,spend_cap
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - rest-client/2.0.0 (darwin16.3.0 x86_64) ruby/2.2.6p396
16
+ Host:
17
+ - graph.facebook.com
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Access-Control-Allow-Origin:
24
+ - "*"
25
+ Etag:
26
+ - '"3093fb2c3c70fd686df36b0d287b0e7bfb65cb68"'
27
+ Pragma:
28
+ - no-cache
29
+ Cache-Control:
30
+ - private, no-cache, no-store, must-revalidate
31
+ Facebook-Api-Version:
32
+ - v2.8
33
+ Expires:
34
+ - Sat, 01 Jan 2000 00:00:00 GMT
35
+ Content-Type:
36
+ - application/json; charset=UTF-8
37
+ X-Fb-Trace-Id:
38
+ - DUi9h6Na23I
39
+ X-Fb-Rev:
40
+ - '2769824'
41
+ Vary:
42
+ - Accept-Encoding
43
+ Content-Encoding:
44
+ - gzip
45
+ X-Fb-Debug:
46
+ - PNBIKRQfFP8ih7Pci3/yzuOwZsjTBbk/ZgYMC/sy8EgEdnMFm95vMqyVgGtzmwkw5pszlRXz1qS1vkgDPDvtHw==
47
+ Date:
48
+ - Tue, 10 Jan 2017 07:38:21 GMT
49
+ Connection:
50
+ - keep-alive
51
+ Content-Length:
52
+ - '242'
53
+ body:
54
+ encoding: ASCII-8BIT
55
+ string: !binary |-
56
+ H4sIAAAAAAAAA22OwWrDMAyGX2X4vICUpk7iW8l66KUdS7odjZMoxYM6IbYL
57
+ Zezdp2Sww+hN6Pv+X/oSthdKSJBltpGQStjm4lmYrhujC3qFCFssNwVigUVa
58
+ wMLbeLfuosN9IhZ256o5nI6874zT0ZP2E7led2YSKsyRGIxusJc4U699MCF6
59
+ jr3uzvX+ZUnNZAKTYK9LXQooEygSSBtAhZnKygRyADZpGKgL9kYPWpxZ0x/U
60
+ ehvoqRrdjWZvR+cZju3nb5CN6nR837/V/HHNhIvm8Ph0KhX+nY5T/+/JPAFk
61
+ uUE2Ua0zm98/F4f8j1MBAAA=
62
+ http_version:
63
+ recorded_at: Tue, 10 Jan 2017 07:38:21 GMT
64
+ - request:
65
+ method: post
66
+ uri: https://graph.facebook.com/v2.8/act_1051938118182807/adsets
67
+ body:
68
+ encoding: UTF-8
69
+ string: campaign_id=6069436026057&name=Test&targeting=%7B%22age_max%22%3A65%2C%22age_min%22%3A18%2C%22app_install_state%22%3A%22not_installed%22%2C%22excluded_custom_audiences%22%3A%5B%7B%22name%22%3A%22All-Users-2016-07-28%22%2C%22id%22%3A%226068994792257%22%7D%5D%2C%22genders%22%3A%5B2%5D%2C%22geo_locations%22%3A%7B%22countries%22%3A%5B%22US%22%5D%2C%22location_types%22%3A%5B%22home%22%2C%22recent%22%5D%7D%2C%22locales%22%3A%5B24%2C6%5D%2C%22publisher_platforms%22%3A%5B%22facebook%22%2C%22instagram%22%2C%22audience_network%22%5D%2C%22device_platforms%22%3A%5B%22desktop%22%5D%2C%22facebook_positions%22%3A%5B%22feed%22%2C%22right_hand_column%22%5D%7D&promoted_object=%7B%22pixel_id%22%3A%221472889202927380%22%2C%22custom_event_type%22%3A%22PURCHASE%22%7D&optimization_goal=OFFSITE_CONVERSIONS&daily_budget=1000&billing_event=IMPRESSIONS&status=ACTIVE&is_autobid=true&access_token=TEST_ACCESS_TOKEN
70
+ headers:
71
+ Accept:
72
+ - "*/*"
73
+ Accept-Encoding:
74
+ - gzip, deflate
75
+ User-Agent:
76
+ - rest-client/2.0.0 (darwin16.3.0 x86_64) ruby/2.2.6p396
77
+ Content-Length:
78
+ - '1061'
79
+ Content-Type:
80
+ - application/x-www-form-urlencoded
81
+ Host:
82
+ - graph.facebook.com
83
+ response:
84
+ status:
85
+ code: 200
86
+ message: OK
87
+ headers:
88
+ P3p:
89
+ - 'CP="Facebook does not have a P3P policy. Learn why here: http://fb.me/p3p"'
90
+ Access-Control-Allow-Origin:
91
+ - "*"
92
+ Pragma:
93
+ - no-cache
94
+ Cache-Control:
95
+ - private, no-cache, no-store, must-revalidate
96
+ Facebook-Api-Version:
97
+ - v2.8
98
+ Expires:
99
+ - Sat, 01 Jan 2000 00:00:00 GMT
100
+ Content-Type:
101
+ - application/json; charset=UTF-8
102
+ X-Fb-Trace-Id:
103
+ - AwRM00wrgYX
104
+ X-Fb-Rev:
105
+ - '2769824'
106
+ Set-Cookie:
107
+ - sW=1484033901%3AAaBh0wN0r79WkD0T; path=/; domain=.graph.facebook.com; secure
108
+ X-Fb-Debug:
109
+ - qPat9POKPd9oGXI3rw0jKoygmTYkHzHEW3Lz10stQiKAoK3uXN0J7bB2FrbNcgnoHZLfHnN0m7oXnSpa0LDK2Q==
110
+ Date:
111
+ - Tue, 10 Jan 2017 07:38:22 GMT
112
+ Connection:
113
+ - keep-alive
114
+ Content-Length:
115
+ - '22'
116
+ body:
117
+ encoding: UTF-8
118
+ string: '{"id":"6081945233457"}'
119
+ http_version:
120
+ recorded_at: Tue, 10 Jan 2017 07:38:22 GMT
121
+ - request:
122
+ method: get
123
+ uri: https://graph.facebook.com/v2.8/6081945233457?access_token=TEST_ACCESS_TOKEN&fields=id,account_id,campaign_id,name,status,configured_status,effective_status,bid_amount,billing_event,optimization_goal,pacing_type,daily_budget,budget_remaining,lifetime_budget,promoted_object,targeting,created_time,updated_time
124
+ body:
125
+ encoding: US-ASCII
126
+ string: ''
127
+ headers:
128
+ Accept:
129
+ - "*/*"
130
+ Accept-Encoding:
131
+ - gzip, deflate
132
+ User-Agent:
133
+ - rest-client/2.0.0 (darwin16.3.0 x86_64) ruby/2.2.6p396
134
+ Host:
135
+ - graph.facebook.com
136
+ response:
137
+ status:
138
+ code: 200
139
+ message: OK
140
+ headers:
141
+ Access-Control-Allow-Origin:
142
+ - "*"
143
+ Etag:
144
+ - '"0983c34785b31e38d0cf8f37ed607f5a8291d0cd"'
145
+ Pragma:
146
+ - no-cache
147
+ Cache-Control:
148
+ - private, no-cache, no-store, must-revalidate
149
+ Facebook-Api-Version:
150
+ - v2.8
151
+ Expires:
152
+ - Sat, 01 Jan 2000 00:00:00 GMT
153
+ Content-Type:
154
+ - application/json; charset=UTF-8
155
+ X-Fb-Trace-Id:
156
+ - AM3sukRLuz3
157
+ X-Fb-Rev:
158
+ - '2769824'
159
+ Vary:
160
+ - Accept-Encoding
161
+ Content-Encoding:
162
+ - gzip
163
+ X-Fb-Debug:
164
+ - wluPtKeCIEfsitUpt6Q66u1Q4wvfvEno0Nm4AvxgyjpQ7yBYG4oBOq83X8Bgjun4quG/9QYEgHrHu7fVPqHR7A==
165
+ Date:
166
+ - Tue, 10 Jan 2017 07:38:22 GMT
167
+ Connection:
168
+ - keep-alive
169
+ Content-Length:
170
+ - '578'
171
+ body:
172
+ encoding: ASCII-8BIT
173
+ string: !binary |-
174
+ H4sIAAAAAAAAA41SwW7iMBD9F59BShwICTfE0l0OpaiBXqrKMs4QvDi25Thd
175
+ uoh/37EBtau97M0z82bem+c5E1mTKcmTIi1HY5plo/GEDAgXwvTas1hMk3Fa
176
+ ZkWaFmlBiyTUBW8tl41mt+68HGV5QvMkdmveAqY30HmMOs9932E8m2+WL4vQ
177
+ bfReNr2Dmv1bhP0ehJfv8Fmbzx7Xs+X3FVvPttXiG4J2UimpGwbvoD0ilo/r
178
+ 50VVLZ9WFVaN9bKVv7mXRrPGcIWIp4eHarlZsPnT6mXxfEdaLsIY/2FR8GuQ
179
+ qmvuavI2IDWX6oPt+roBH01IkkAcY+ag5VJja6iMMa/kHpAUPhsC2jrTGo9r
180
+ mt1PXIpMz8TKE6ibr6MJLYqSJrSkk6wIDaLvvGmva91UkfX2ef5jVi3IZUA8
181
+ dzg98p4Jb4C1/ESm+XhwDaQm07TAwFomNW6jVHQxjNHG33NQB59PQvU1artx
182
+ 8r6WoAWg4a/n+1XkRVmOJiWlX/91ptRw24HrhjRJ82FKh0lKLmhZA7rGNA6g
183
+ MTJMGRF/oQt640k5GRnItgom3+tx15g/GOQYEAci/Ozb5YpRsUhHg/ztiwns
184
+ 60ejMDhZrrswDpcM9vc7JbsDOGYV93vj2kix5wJ2xhwREQ1pHG/Dzd8MYBr8
185
+ L+OOQd8dyqzp5G0RHADRQSebg2cHPBkmjOpbHc8G3iXO+Iuwhu7ojY3bCAc8
186
+ XEQ4FpSMDk7QvmFSbmg2zYopxXcRT6239X8hL38ARmr8p8QDAAA=
187
+ http_version:
188
+ recorded_at: Tue, 10 Jan 2017 07:38:22 GMT
189
+ recorded_with: VCR 3.0.3
@@ -0,0 +1,124 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://graph.facebook.com/v2.8/6081945233457?access_token=TEST_ACCESS_TOKEN&fields=id,account_id,campaign_id,name,status,configured_status,effective_status,bid_amount,billing_event,optimization_goal,pacing_type,daily_budget,budget_remaining,lifetime_budget,promoted_object,targeting,created_time,updated_time
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - "*/*"
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - rest-client/2.0.0 (darwin16.3.0 x86_64) ruby/2.2.6p396
16
+ Host:
17
+ - graph.facebook.com
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Access-Control-Allow-Origin:
24
+ - "*"
25
+ Etag:
26
+ - '"0983c34785b31e38d0cf8f37ed607f5a8291d0cd"'
27
+ Pragma:
28
+ - no-cache
29
+ Cache-Control:
30
+ - private, no-cache, no-store, must-revalidate
31
+ Facebook-Api-Version:
32
+ - v2.8
33
+ Expires:
34
+ - Sat, 01 Jan 2000 00:00:00 GMT
35
+ Content-Type:
36
+ - application/json; charset=UTF-8
37
+ X-Fb-Trace-Id:
38
+ - DBFCj3ipgSr
39
+ X-Fb-Rev:
40
+ - '2769824'
41
+ Vary:
42
+ - Accept-Encoding
43
+ Content-Encoding:
44
+ - gzip
45
+ X-Fb-Debug:
46
+ - AZ7nHqabtntJxydYIChMjiwtsfqoRPKiLQ8/IBmYKniFQ+E+cG66ht6U2DLsiAYEaBZVcKxdxTTjZogNXlGGEQ==
47
+ Date:
48
+ - Tue, 10 Jan 2017 07:39:49 GMT
49
+ Connection:
50
+ - keep-alive
51
+ Content-Length:
52
+ - '578'
53
+ body:
54
+ encoding: ASCII-8BIT
55
+ string: !binary |-
56
+ H4sIAAAAAAAAA41SwW7iMBD9F59BShwICTfE0l0OpaiBXqrKMs4QvDi25Thd
57
+ uoh/37EBtau97M0z82bem+c5E1mTKcmTIi1HY5plo/GEDAgXwvTas1hMk3Fa
58
+ ZkWaFmlBiyTUBW8tl41mt+68HGV5QvMkdmveAqY30HmMOs9932E8m2+WL4vQ
59
+ bfReNr2Dmv1bhP0ehJfv8Fmbzx7Xs+X3FVvPttXiG4J2UimpGwbvoD0ilo/r
60
+ 50VVLZ9WFVaN9bKVv7mXRrPGcIWIp4eHarlZsPnT6mXxfEdaLsIY/2FR8GuQ
61
+ qmvuavI2IDWX6oPt+roBH01IkkAcY+ag5VJja6iMMa/kHpAUPhsC2jrTGo9r
62
+ mt1PXIpMz8TKE6ibr6MJLYqSJrSkk6wIDaLvvGmva91UkfX2ef5jVi3IZUA8
63
+ dzg98p4Jb4C1/ESm+XhwDaQm07TAwFomNW6jVHQxjNHG33NQB59PQvU1artx
64
+ 8r6WoAWg4a/n+1XkRVmOJiWlX/91ptRw24HrhjRJ82FKh0lKLmhZA7rGNA6g
65
+ MTJMGRF/oQt640k5GRnItgom3+tx15g/GOQYEAci/Ozb5YpRsUhHg/ztiwns
66
+ 60ejMDhZrrswDpcM9vc7JbsDOGYV93vj2kix5wJ2xhwREQ1pHG/Dzd8MYBr8
67
+ L+OOQd8dyqzp5G0RHADRQSebg2cHPBkmjOpbHc8G3iXO+Iuwhu7ojY3bCAc8
68
+ XEQ4FpSMDk7QvmFSbmg2zYopxXcRT6239X8hL38ARmr8p8QDAAA=
69
+ http_version:
70
+ recorded_at: Tue, 10 Jan 2017 07:39:49 GMT
71
+ - request:
72
+ method: delete
73
+ uri: https://graph.facebook.com/v2.8/6081945233457?access_token=TEST_ACCESS_TOKEN
74
+ body:
75
+ encoding: US-ASCII
76
+ string: ''
77
+ headers:
78
+ Accept:
79
+ - "*/*"
80
+ Accept-Encoding:
81
+ - gzip, deflate
82
+ User-Agent:
83
+ - rest-client/2.0.0 (darwin16.3.0 x86_64) ruby/2.2.6p396
84
+ Host:
85
+ - graph.facebook.com
86
+ response:
87
+ status:
88
+ code: 200
89
+ message: OK
90
+ headers:
91
+ P3p:
92
+ - 'CP="Facebook does not have a P3P policy. Learn why here: http://fb.me/p3p"'
93
+ Access-Control-Allow-Origin:
94
+ - "*"
95
+ Pragma:
96
+ - no-cache
97
+ Cache-Control:
98
+ - private, no-cache, no-store, must-revalidate
99
+ Facebook-Api-Version:
100
+ - v2.8
101
+ Expires:
102
+ - Sat, 01 Jan 2000 00:00:00 GMT
103
+ Content-Type:
104
+ - application/json; charset=UTF-8
105
+ X-Fb-Trace-Id:
106
+ - AKVHkQrgYjj
107
+ X-Fb-Rev:
108
+ - '2769824'
109
+ Set-Cookie:
110
+ - sW=1484033990%3AAaAd4deeT2KlMMk2; path=/; domain=.graph.facebook.com; secure
111
+ X-Fb-Debug:
112
+ - 4NAqA+2lkZSqcoAQnNc09Kgsxu7YkAPWvcdh8WQiVpcotRf7ov5BnzAWr5qnXYVGxmKcQemTl0V9LTaREiSWiQ==
113
+ Date:
114
+ - Tue, 10 Jan 2017 07:39:50 GMT
115
+ Connection:
116
+ - keep-alive
117
+ Content-Length:
118
+ - '16'
119
+ body:
120
+ encoding: UTF-8
121
+ string: '{"success":true}'
122
+ http_version:
123
+ recorded_at: Tue, 10 Jan 2017 07:39:50 GMT
124
+ recorded_with: VCR 3.0.3
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facebook_ads
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Estreich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-09 00:00:00.000000000 Z
11
+ date: 2017-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -62,6 +62,7 @@ files:
62
62
  - lib/facebook_ads/ad_audience.rb
63
63
  - lib/facebook_ads/ad_campaign.rb
64
64
  - lib/facebook_ads/ad_creative.rb
65
+ - lib/facebook_ads/ad_exception.rb
65
66
  - lib/facebook_ads/ad_image.rb
66
67
  - lib/facebook_ads/ad_insight.rb
67
68
  - lib/facebook_ads/ad_product.rb
@@ -95,6 +96,8 @@ files:
95
96
  - test/vcr_cassettes/AdProductCatalogTest-test_all.yml
96
97
  - test/vcr_cassettes/AdProductCatalogTest-test_create.yml
97
98
  - test/vcr_cassettes/AdProductTest-test_list.yml
99
+ - test/vcr_cassettes/AdSetTest-test_create.yml
100
+ - test/vcr_cassettes/AdSetTest-test_destroy.yml
98
101
  - test/vcr_cassettes/AdSetTest-test_update.yml
99
102
  homepage: https://github.com/cte/facebook-ruby-ads-sdk
100
103
  licenses: