facebook_ads 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: