facebook_ads 0.1.11 → 0.1.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.approvals +0 -0
- data/.coveralls.yml +1 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -1
- data/.rubocop_todo.yml +16 -0
- data/.travis.yml +3 -1
- data/CHANGELOG.md +5 -0
- data/Gemfile +10 -7
- data/Gemfile.lock +56 -19
- data/LICENSE.md +22 -0
- data/README.md +8 -0
- data/facebook_ads.gemspec +2 -2
- data/lib/facebook_ads/ad.rb +2 -2
- data/lib/facebook_ads/ad_account.rb +52 -19
- data/lib/facebook_ads/ad_audience.rb +1 -1
- data/lib/facebook_ads/ad_campaign.rb +47 -5
- data/lib/facebook_ads/ad_creative.rb +4 -4
- data/lib/facebook_ads/ad_exception.rb +7 -1
- data/lib/facebook_ads/ad_image.rb +6 -2
- data/lib/facebook_ads/ad_insight.rb +1 -1
- data/lib/facebook_ads/ad_product.rb +1 -1
- data/lib/facebook_ads/ad_product_catalog.rb +1 -1
- data/lib/facebook_ads/ad_product_feed.rb +1 -1
- data/lib/facebook_ads/ad_product_set.rb +1 -1
- data/lib/facebook_ads/ad_set.rb +5 -5
- data/lib/facebook_ads/ad_targeting.rb +3 -3
- data/lib/facebook_ads/base.rb +10 -9
- data/spec/facebook_ads/ad_account_spec.rb +93 -0
- data/spec/facebook_ads/ad_campaign_spec.rb +19 -0
- data/spec/facebook_ads/ad_creative_spec.rb +4 -0
- data/spec/facebook_ads/ad_image_spec.rb +4 -0
- data/spec/facebook_ads/ad_insight_spec.rb +4 -0
- data/spec/facebook_ads/ad_product_catalog_spec.rb +27 -0
- data/spec/facebook_ads/ad_product_feed_spec.rb +4 -0
- data/spec/facebook_ads/ad_product_set_spec.rb +4 -0
- data/spec/facebook_ads/ad_product_spec.rb +21 -0
- data/spec/facebook_ads/ad_set_spec.rb +47 -0
- data/spec/facebook_ads/ad_spec.rb +4 -0
- data/spec/facebook_ads/ad_targeting_spec.rb +4 -0
- data/spec/facebook_ads/facebook_ads_spec.rb +15 -0
- data/spec/fixtures/approvals/facebookads_adaccount/ad_campaigns/lists_campaigns.approved.json +15 -0
- data/spec/fixtures/approvals/facebookads_adaccount/ad_creatives/lists_creatives.approved.json +1047 -0
- data/spec/fixtures/approvals/facebookads_adaccount/ad_images/lists_images.approved.json +11 -0
- data/spec/fixtures/approvals/facebookads_adaccount/ad_sets/lists_ad_sets.approved.json +3 -0
- data/spec/fixtures/approvals/facebookads_adaccount/ads/lists_ads.approved.json +3 -0
- data/spec/fixtures/approvals/facebookads_adaccount/all/lists_all_accounts.approved.json +92 -0
- data/spec/fixtures/approvals/facebookads_adaccount/create_ad_campaign/creates_a_new_ad_campaign.approved.json +13 -0
- data/spec/fixtures/approvals/facebookads_adaccount/create_ad_images/creates_an_image.approved.json +11 -0
- data/spec/fixtures/approvals/facebookads_adaccount/find_by/finds_a_specific_account.approved.json +9 -0
- data/spec/fixtures/approvals/facebookads_adaccount/reach_estimate/estimates_the_reach_of_a_targeting_spec.approved.json +358 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_campaigns/lists_campaigns.yml +56 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_creatives/lists_creatives.yml +91 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_images/lists_images.yml +56 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_sets/lists_ad_sets.yml +56 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ads/lists_ads.yml +56 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_all/lists_all_accounts.yml +58 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_create_ad_campaign/creates_a_new_ad_campaign.yml +115 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_create_ad_images/creates_an_image.yml +2865 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_find_by/finds_a_specific_account.yml +58 -0
- data/spec/fixtures/cassettes/FacebookAds_AdAccount/_reach_estimate/estimates_the_reach_of_a_targeting_spec.yml +56 -0
- data/spec/fixtures/cassettes/FacebookAds_AdCampaign/_destroy/creates_a_new_ad_campaign.yml +164 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/approvals.rb +10 -0
- data/spec/support/facebook_ads.rb +4 -0
- data/spec/support/rest_client.rb +13 -0
- data/spec/support/vcr.rb +16 -0
- metadata +47 -29
- data/test/ad_account_test.rb +0 -27
- data/test/ad_campaign_test.rb +0 -32
- data/test/ad_creative_test.rb +0 -7
- data/test/ad_image_test.rb +0 -27
- data/test/ad_insight_test.rb +0 -7
- data/test/ad_product_catalog_test.rb +0 -28
- data/test/ad_product_feed_test.rb +0 -7
- data/test/ad_product_set_test.rb +0 -7
- data/test/ad_product_test.rb +0 -22
- data/test/ad_set_test.rb +0 -48
- data/test/ad_targeting_test.rb +0 -7
- data/test/ad_test.rb +0 -7
- data/test/facebook_ads_test.rb +0 -8
- data/test/test_helper.rb +0 -64
- data/test/vcr_cassettes/AdAccountTest-test_all.yml +0 -70
- data/test/vcr_cassettes/AdAccountTest-test_applications.yml +0 -130
- data/test/vcr_cassettes/AdAccountTest-test_find_by.yml +0 -71
- data/test/vcr_cassettes/AdCampaignTest-test_create.yml +0 -295
- data/test/vcr_cassettes/AdCampaignTest-test_list.yml +0 -133
- data/test/vcr_cassettes/AdImageTest-test_create.yml +0 -2963
- data/test/vcr_cassettes/AdImageTest-test_list.yml +0 -137
- data/test/vcr_cassettes/AdProductCatalogTest-test_all.yml +0 -60
- data/test/vcr_cassettes/AdProductCatalogTest-test_create.yml +0 -256
- data/test/vcr_cassettes/AdProductTest-test_list.yml +0 -130
- data/test/vcr_cassettes/AdSetTest-test_create.yml +0 -189
- data/test/vcr_cassettes/AdSetTest-test_destroy.yml +0 -124
- data/test/vcr_cassettes/AdSetTest-test_update.yml +0 -134
@@ -2,9 +2,51 @@ module FacebookAds
|
|
2
2
|
# An ad campaign has many ad sets and belongs to an ad account.
|
3
3
|
# https://developers.facebook.com/docs/marketing-api/reference/ad-campaign-group
|
4
4
|
class AdCampaign < Base
|
5
|
-
FIELDS
|
6
|
-
|
7
|
-
|
5
|
+
FIELDS = %w[
|
6
|
+
id
|
7
|
+
account_id
|
8
|
+
buying_type
|
9
|
+
can_use_spend_cap
|
10
|
+
configured_status
|
11
|
+
created_time
|
12
|
+
effective_status
|
13
|
+
name
|
14
|
+
objective
|
15
|
+
start_time
|
16
|
+
stop_time
|
17
|
+
updated_time spend_cap
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
STATUSES = %w[
|
21
|
+
ACTIVE PAUSED
|
22
|
+
DELETED
|
23
|
+
PENDING_REVIEW
|
24
|
+
DISAPPROVED
|
25
|
+
PREAPPROVED
|
26
|
+
PENDING_BILLING_INFO
|
27
|
+
CAMPAIGN_PAUSED
|
28
|
+
ARCHIVED
|
29
|
+
ADSET_PAUSED
|
30
|
+
].freeze
|
31
|
+
|
32
|
+
OBJECTIVES = %w[
|
33
|
+
BRAND_AWARENESS
|
34
|
+
CANVAS_APP_ENGAGEMENT
|
35
|
+
CANVAS_APP_INSTALLS
|
36
|
+
EVENT_RESPONSES
|
37
|
+
LEAD_GENERATION
|
38
|
+
LOCAL_AWARENESS
|
39
|
+
MOBILE_APP_ENGAGEMENT
|
40
|
+
MOBILE_APP_INSTALLS
|
41
|
+
NONE
|
42
|
+
OFFER_CLAIMS
|
43
|
+
PAGE_LIKES
|
44
|
+
POST_ENGAGEMENT
|
45
|
+
LINK_CLICKS
|
46
|
+
CONVERSIONS
|
47
|
+
VIDEO_VIEWS
|
48
|
+
PRODUCT_CATALOG_SALES
|
49
|
+
].freeze
|
8
50
|
|
9
51
|
# belongs_to ad_account
|
10
52
|
|
@@ -19,8 +61,8 @@ module FacebookAds
|
|
19
61
|
end
|
20
62
|
|
21
63
|
def create_ad_set(name:, promoted_object:, targeting:, daily_budget:, optimization_goal:, billing_event: 'IMPRESSIONS', status: 'ACTIVE', is_autobid: true)
|
22
|
-
raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.
|
23
|
-
raise Exception, "Billing event must be one of: #{AdSet::BILLING_EVENTS.
|
64
|
+
raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
|
65
|
+
raise Exception, "Billing event must be one of: #{AdSet::BILLING_EVENTS.join(', ')}" unless AdSet::BILLING_EVENTS.include?(billing_event)
|
24
66
|
|
25
67
|
if targeting.is_a?(Hash)
|
26
68
|
# NOP
|
@@ -2,8 +2,8 @@ module FacebookAds
|
|
2
2
|
# Ad ad creative has many ad images and belongs to an ad account.
|
3
3
|
# https://developers.facebook.com/docs/marketing-api/reference/ad-creative
|
4
4
|
class AdCreative < Base
|
5
|
-
FIELDS = %w
|
6
|
-
CALL_TO_ACTION_TYPES = %w
|
5
|
+
FIELDS = %w[id name object_story_id object_story_spec object_type thumbnail_url run_status].freeze
|
6
|
+
CALL_TO_ACTION_TYPES = %w[SHOP_NOW INSTALL_MOBILE_APP USE_MOBILE_APP SIGN_UP DOWNLOAD BUY_NOW].freeze
|
7
7
|
|
8
8
|
class << self
|
9
9
|
def photo(name:, page_id:, instagram_actor_id: nil, message:, link:, link_title:, image_hash:, call_to_action_type:)
|
@@ -54,7 +54,6 @@ module FacebookAds
|
|
54
54
|
}
|
55
55
|
}
|
56
56
|
|
57
|
-
|
58
57
|
{
|
59
58
|
name: name,
|
60
59
|
object_story_spec: object_story_spec.to_json
|
@@ -62,7 +61,8 @@ module FacebookAds
|
|
62
61
|
end
|
63
62
|
|
64
63
|
def product_set(name:, page_id:, link:, message:, headline:, description:, product_set_id:)
|
65
|
-
{
|
64
|
+
{
|
65
|
+
name: name,
|
66
66
|
object_story_spec: {
|
67
67
|
page_id: page_id,
|
68
68
|
template_data: {
|
@@ -3,7 +3,7 @@ module FacebookAds
|
|
3
3
|
# An image will always produce the same hash.
|
4
4
|
# https://developers.facebook.com/docs/marketing-api/reference/ad-image
|
5
5
|
class AdImage < Base
|
6
|
-
FIELDS = %w
|
6
|
+
FIELDS = %w[id hash account_id name permalink_url original_width original_height].freeze
|
7
7
|
|
8
8
|
class << self
|
9
9
|
def find(_id)
|
@@ -11,6 +11,10 @@ module FacebookAds
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
# @TODO:
|
15
|
+
# You are setting a key that conflicts with a built-in method FacebookAds::AdImage#hash defined in Hash.
|
16
|
+
# This can cause unexpected behavior when accessing the key via as a property.
|
17
|
+
# You can still access the key via the #[] method.
|
14
18
|
def hash
|
15
19
|
self[:hash]
|
16
20
|
end
|
@@ -20,7 +24,7 @@ module FacebookAds
|
|
20
24
|
end
|
21
25
|
|
22
26
|
def destroy
|
23
|
-
super(path: "/act_#{account_id}/adimages", query: { hash: hash })
|
27
|
+
super(path: "/act_#{account_id}/adimages", query: { hash: self[:hash] })
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -4,7 +4,7 @@ module FacebookAds
|
|
4
4
|
# https://developers.facebook.com/docs/marketing-api/insights/overview
|
5
5
|
# https://developers.facebook.com/docs/marketing-api/insights/fields/v2.8
|
6
6
|
class AdInsight < Base
|
7
|
-
FIELDS = %w
|
7
|
+
FIELDS = %w[account_id campaign_id adset_id ad_id objective impressions unique_actions cost_per_unique_action_type clicks cpc cpm cpp ctr spend reach relevance_score].freeze
|
8
8
|
|
9
9
|
class << self
|
10
10
|
def find(_id)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module FacebookAds
|
2
2
|
# https://developers.facebook.com/docs/marketing-api/reference/product-item
|
3
3
|
class AdProduct < Base
|
4
|
-
FIELDS = %w
|
4
|
+
FIELDS = %w[id retailer_id name description brand category currency price image_url url].freeze
|
5
5
|
end
|
6
6
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module FacebookAds
|
2
2
|
# https://developers.facebook.com/docs/marketing-api/reference/product-catalog
|
3
3
|
class AdProductCatalog < Base
|
4
|
-
FIELDS = %w
|
4
|
+
FIELDS = %w[id name vertical product_count feed_count].freeze
|
5
5
|
|
6
6
|
class << self
|
7
7
|
def all(query = {})
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module FacebookAds
|
2
2
|
# https://developers.facebook.com/docs/marketing-api/reference/product-feed
|
3
3
|
class AdProductFeed < Base
|
4
|
-
FIELDS = %w
|
4
|
+
FIELDS = %w[id country created_time default_currency deletion_enabled delimiter encoding file_name latest_upload name product_count quoted_fields_mode schedule].freeze
|
5
5
|
end
|
6
6
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module FacebookAds
|
2
2
|
# https://developers.facebook.com/docs/marketing-api/reference/product-set
|
3
3
|
class AdProductSet < Base
|
4
|
-
FIELDS = %w
|
4
|
+
FIELDS = %w[id auto_creation_url filter name product_catalog product_count].freeze
|
5
5
|
end
|
6
6
|
end
|
data/lib/facebook_ads/ad_set.rb
CHANGED
@@ -20,7 +20,7 @@ module FacebookAds
|
|
20
20
|
# ).freeze
|
21
21
|
|
22
22
|
# Fields we might actually care about:
|
23
|
-
FIELDS = %w
|
23
|
+
FIELDS = %w[
|
24
24
|
id account_id campaign_id
|
25
25
|
name
|
26
26
|
status configured_status effective_status
|
@@ -29,11 +29,11 @@ module FacebookAds
|
|
29
29
|
promoted_object
|
30
30
|
targeting
|
31
31
|
created_time updated_time
|
32
|
-
|
32
|
+
].freeze
|
33
33
|
|
34
|
-
STATUSES = %w
|
35
|
-
BILLING_EVENTS = %w
|
36
|
-
OPTIMIZATION_GOALS = %w
|
34
|
+
STATUSES = %w[ACTIVE PAUSED DELETED PENDING_REVIEW DISAPPROVED PREAPPROVED PENDING_BILLING_INFO CAMPAIGN_PAUSED ARCHIVED ADSET_PAUSED].freeze
|
35
|
+
BILLING_EVENTS = %w[APP_INSTALLS IMPRESSIONS].freeze
|
36
|
+
OPTIMIZATION_GOALS = %w[APP_INSTALLS OFFSITE_CONVERSIONS].freeze
|
37
37
|
|
38
38
|
# belongs_to ad_account
|
39
39
|
|
@@ -7,8 +7,8 @@ module FacebookAds
|
|
7
7
|
ANDROID_OS = 'Android'.freeze
|
8
8
|
APPLE_OS = 'iOS'.freeze
|
9
9
|
OSES = [ANDROID_OS, APPLE_OS].freeze
|
10
|
-
ANDROID_DEVICES = %w
|
11
|
-
APPLE_DEVICES = %w
|
10
|
+
ANDROID_DEVICES = %w[Android_Smartphone Android_Tablet].freeze
|
11
|
+
APPLE_DEVICES = %w[iPhone iPad iPod].freeze
|
12
12
|
DEVICES = ANDROID_DEVICES + APPLE_DEVICES
|
13
13
|
INSTALLED = 'installed'.freeze
|
14
14
|
NOT_INSTALLED = 'not_installed'.freeze
|
@@ -53,7 +53,7 @@ module FacebookAds
|
|
53
53
|
user_os: user_os,
|
54
54
|
user_device: user_device,
|
55
55
|
app_install_state: app_install_state
|
56
|
-
}.
|
56
|
+
}.reject { |_k, v| v.nil? }
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
data/lib/facebook_ads/base.rb
CHANGED
@@ -11,7 +11,7 @@ module FacebookAds
|
|
11
11
|
uri = "#{FacebookAds.base_uri}#{path}?" + build_nested_query(query)
|
12
12
|
FacebookAds.logger.debug "GET #{uri}"
|
13
13
|
response = begin
|
14
|
-
RestClient.get(uri)
|
14
|
+
RestClient.get(uri, accept: :json, accept_encoding: :identity)
|
15
15
|
rescue RestClient::Exception => e
|
16
16
|
exception(:get, path, e)
|
17
17
|
end
|
@@ -75,6 +75,7 @@ module FacebookAds
|
|
75
75
|
|
76
76
|
hash.each_pair do |key, value|
|
77
77
|
# https://github.com/intridea/hashie/blob/master/lib/hashie/mash.rb#L111
|
78
|
+
# key = '_hash' if key == 'hash'
|
78
79
|
object.custom_writer(key, value, false)
|
79
80
|
end
|
80
81
|
|
@@ -137,15 +138,15 @@ module FacebookAds
|
|
137
138
|
begin
|
138
139
|
if (error = JSON.parse(response)['error']).nil?
|
139
140
|
response
|
141
|
+
elsif error['error_subcode'].nil? || error['error_user_title'].nil? || error['error_user_msg'].nil?
|
142
|
+
"#{error['type']} / #{error['code']}: #{error['message']}"
|
140
143
|
else
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
"#{error['error_subcode']} / #{error['error_user_title']}: #{error['error_user_msg']}"
|
148
|
-
end
|
144
|
+
exception = AdException.new(
|
145
|
+
code: error['error_subcode'],
|
146
|
+
title: error['error_user_title'],
|
147
|
+
message: error['error_user_msg']
|
148
|
+
)
|
149
|
+
"#{exception.code} / #{exception.title}: #{exception.message}"
|
149
150
|
end
|
150
151
|
rescue JSON::ParserError
|
151
152
|
response
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# FACEBOOK_ACCESS_TOKEN=... rspec spec/facebook_ads/ad_account_spec.rb
|
4
|
+
describe FacebookAds::AdAccount do
|
5
|
+
let(:account) do
|
6
|
+
FacebookAds::AdAccount.new(
|
7
|
+
id: 'act_10152335766987003',
|
8
|
+
account_id: '10152335766987003',
|
9
|
+
account_status: 1,
|
10
|
+
age: 466.0,
|
11
|
+
created_time: '2014-10-24T14:38:31-0700',
|
12
|
+
currency: 'USD',
|
13
|
+
name: 'Chris Estreich'
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#all' do
|
18
|
+
it 'lists all accounts', :vcr do
|
19
|
+
accounts = FacebookAds::AdAccount.all
|
20
|
+
verify(format: :json) { JSON.dump(accounts) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#find_by' do
|
25
|
+
it 'finds a specific account', :vcr do
|
26
|
+
account = FacebookAds::AdAccount.find_by(name: 'iOS')
|
27
|
+
verify(format: :json) { JSON.dump(account) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.ad_campaigns' do
|
32
|
+
it 'lists campaigns', :vcr do
|
33
|
+
ad_campaigns = account.ad_campaigns
|
34
|
+
verify(format: :json) { JSON.dump(ad_campaigns) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '.create_ad_campaign' do
|
39
|
+
it 'creates a new ad campaign', :vcr do
|
40
|
+
ad_campaign = account.create_ad_campaign(name: 'Test', objective: 'MOBILE_APP_INSTALLS')
|
41
|
+
verify(format: :json) { JSON.dump(ad_campaign) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '.ad_images' do
|
46
|
+
it 'lists images', :vcr do
|
47
|
+
ad_images = account.ad_images(hashes: %w[d8fc613662fb5ef6cf5fb9d1fe779315])
|
48
|
+
verify(format: :json) { JSON.dump(ad_images) }
|
49
|
+
expect(ad_images.first.hash).to eq('d8fc613662fb5ef6cf5fb9d1fe779315')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '.create_ad_images' do
|
54
|
+
it 'creates an image', :vcr do
|
55
|
+
ad_images = account.create_ad_images(['https://img0.etsystatic.com/108/1/13006112/il_570xN.1047856494_l2gp.jpg'])
|
56
|
+
verify(format: :json) { JSON.dump(ad_images) }
|
57
|
+
expect(ad_images.first.hash).to eq('d8fc613662fb5ef6cf5fb9d1fe779315')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '.ad_creatives' do
|
62
|
+
it 'lists creatives', :vcr do
|
63
|
+
ad_creatives = account.ad_creatives
|
64
|
+
verify(format: :json) { JSON.dump(ad_creatives) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '.ad_sets' do
|
69
|
+
it 'lists ad sets', :vcr do
|
70
|
+
ad_sets = account.ad_sets
|
71
|
+
verify(format: :json) { JSON.dump(ad_sets) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '.ads' do
|
76
|
+
it 'lists ads', :vcr do
|
77
|
+
ads = account.ads
|
78
|
+
verify(format: :json) { JSON.dump(ads) }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '.reach_estimate' do
|
83
|
+
it 'estimates the reach of a targeting spec', :vcr do
|
84
|
+
targeting = FacebookAds::AdTargeting.new
|
85
|
+
targeting.genders = [FacebookAds::AdTargeting::WOMEN]
|
86
|
+
targeting.age_min = 18
|
87
|
+
targeting.age_max = 20
|
88
|
+
targeting.countries = ['US']
|
89
|
+
reach = account.reach_estimate(targeting: targeting, optimization_goal: 'OFFSITE_CONVERSIONS')
|
90
|
+
verify(format: :json) { JSON.dump(reach) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# FACEBOOK_ACCESS_TOKEN=... rspec spec/facebook_ads/ad_campaign_spec.rb
|
4
|
+
describe FacebookAds::AdCampaign do
|
5
|
+
xdescribe '.ad_sets' do
|
6
|
+
end
|
7
|
+
|
8
|
+
xdescribe '.create_ad_set' do
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.destroy' do
|
12
|
+
it 'creates a new ad campaign', :vcr do
|
13
|
+
ad_campaign = FacebookAds::AdCampaign.find('6076262142242')
|
14
|
+
expect(ad_campaign.destroy).to be(true)
|
15
|
+
ad_campaign = FacebookAds::AdCampaign.find(ad_campaign.id)
|
16
|
+
expect(ad_campaign.effective_status).to eq('DELETED')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FacebookAds::AdProductCatalog do
|
4
|
+
# def test_all
|
5
|
+
# vcr do
|
6
|
+
# catalog = FacebookAds::AdProductCatalog.all.first
|
7
|
+
# assert_equal '197871307315718', catalog.id
|
8
|
+
# assert_equal 'Test', catalog.name
|
9
|
+
# assert_equal 'commerce', catalog.vertical
|
10
|
+
# assert_equal 1, catalog.product_count
|
11
|
+
# assert_equal 1, catalog.feed_count
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# def test_create
|
16
|
+
# vcr do
|
17
|
+
# catalog = FacebookAds::AdProductCatalog.create(name: 'Foo Bar')
|
18
|
+
# assert_equal 'Foo Bar', catalog.name
|
19
|
+
# assert_equal 'commerce', catalog.vertical
|
20
|
+
# assert_equal 0, catalog.product_count
|
21
|
+
# assert_equal 0, catalog.feed_count
|
22
|
+
# catalog = FacebookAds::AdProductCatalog.find(catalog.id)
|
23
|
+
# assert_equal true, catalog.destroy
|
24
|
+
# assert_nil FacebookAds::AdProductCatalog.find_by(name: 'Foo Bar')
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
end
|