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 +4 -4
- data/Gemfile.lock +1 -1
- data/facebook_ads.gemspec +2 -2
- data/lib/facebook_ads/ad_account.rb +8 -7
- data/lib/facebook_ads/ad_audience.rb +3 -1
- data/lib/facebook_ads/ad_campaign.rb +2 -2
- data/lib/facebook_ads/ad_exception.rb +5 -0
- data/lib/facebook_ads/ad_product_catalog.rb +8 -6
- data/lib/facebook_ads/ad_set.rb +32 -3
- data/lib/facebook_ads/base.rb +28 -16
- data/test/ad_set_test.rb +37 -0
- data/test/vcr_cassettes/AdSetTest-test_create.yml +189 -0
- data/test/vcr_cassettes/AdSetTest-test_destroy.yml +124 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6da1d5a4ec51406066404c86c95a51e413617c8
|
4
|
+
data.tar.gz: 8520c0ea1111ea0dd115e819643ac1e10cf6922f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce833767545b4d0e32008e02aab0e3c5e94091a5adc3c08fea5e96b74e2e73528699f503208c31fc267194672ad1d6ef24856445bd5c337c7b261cdbbc897fe0
|
7
|
+
data.tar.gz: d773c3fd49a912fde691380c36af876e704a2a445cd924d76d933ad2ccaafbf8a2cda2cc36959329a2fcc1b171cd9e8b65273639d06686129104f76032b6d8e5
|
data/Gemfile.lock
CHANGED
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.
|
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.
|
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
|
-
|
31
|
-
AdCampaign.
|
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
|
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
|
-
|
109
|
-
AdCreative.find(
|
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
|
-
|
122
|
-
AdCreative.find(
|
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
|
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
|
-
|
44
|
-
AdSet.find(
|
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
|
@@ -17,8 +17,9 @@ module FacebookAds
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def create(name:)
|
20
|
-
|
21
|
-
|
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
|
-
|
34
|
-
|
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
|
-
|
57
|
-
AdProduct.find(
|
58
|
+
result = AdProductCatalog.post("/#{id}/products", query: data)
|
59
|
+
AdProduct.find(result['id'])
|
58
60
|
end
|
59
61
|
end
|
60
62
|
end
|
data/lib/facebook_ads/ad_set.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
30
|
-
Ad.
|
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
|
data/lib/facebook_ads/base.rb
CHANGED
@@ -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: {}
|
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:
|
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,
|
133
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
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
|
-
|
151
|
+
response
|
140
152
|
end
|
141
153
|
else
|
142
|
-
|
154
|
+
response.inspect
|
143
155
|
end
|
144
156
|
|
145
|
-
FacebookAds.logger.error "#{verb.upcase} #{path}
|
146
|
-
raise
|
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
|
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.
|
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-
|
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:
|