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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.approvals +0 -0
  3. data/.coveralls.yml +1 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +13 -1
  6. data/.rubocop_todo.yml +16 -0
  7. data/.travis.yml +3 -1
  8. data/CHANGELOG.md +5 -0
  9. data/Gemfile +10 -7
  10. data/Gemfile.lock +56 -19
  11. data/LICENSE.md +22 -0
  12. data/README.md +8 -0
  13. data/facebook_ads.gemspec +2 -2
  14. data/lib/facebook_ads/ad.rb +2 -2
  15. data/lib/facebook_ads/ad_account.rb +52 -19
  16. data/lib/facebook_ads/ad_audience.rb +1 -1
  17. data/lib/facebook_ads/ad_campaign.rb +47 -5
  18. data/lib/facebook_ads/ad_creative.rb +4 -4
  19. data/lib/facebook_ads/ad_exception.rb +7 -1
  20. data/lib/facebook_ads/ad_image.rb +6 -2
  21. data/lib/facebook_ads/ad_insight.rb +1 -1
  22. data/lib/facebook_ads/ad_product.rb +1 -1
  23. data/lib/facebook_ads/ad_product_catalog.rb +1 -1
  24. data/lib/facebook_ads/ad_product_feed.rb +1 -1
  25. data/lib/facebook_ads/ad_product_set.rb +1 -1
  26. data/lib/facebook_ads/ad_set.rb +5 -5
  27. data/lib/facebook_ads/ad_targeting.rb +3 -3
  28. data/lib/facebook_ads/base.rb +10 -9
  29. data/spec/facebook_ads/ad_account_spec.rb +93 -0
  30. data/spec/facebook_ads/ad_campaign_spec.rb +19 -0
  31. data/spec/facebook_ads/ad_creative_spec.rb +4 -0
  32. data/spec/facebook_ads/ad_image_spec.rb +4 -0
  33. data/spec/facebook_ads/ad_insight_spec.rb +4 -0
  34. data/spec/facebook_ads/ad_product_catalog_spec.rb +27 -0
  35. data/spec/facebook_ads/ad_product_feed_spec.rb +4 -0
  36. data/spec/facebook_ads/ad_product_set_spec.rb +4 -0
  37. data/spec/facebook_ads/ad_product_spec.rb +21 -0
  38. data/spec/facebook_ads/ad_set_spec.rb +47 -0
  39. data/spec/facebook_ads/ad_spec.rb +4 -0
  40. data/spec/facebook_ads/ad_targeting_spec.rb +4 -0
  41. data/spec/facebook_ads/facebook_ads_spec.rb +15 -0
  42. data/spec/fixtures/approvals/facebookads_adaccount/ad_campaigns/lists_campaigns.approved.json +15 -0
  43. data/spec/fixtures/approvals/facebookads_adaccount/ad_creatives/lists_creatives.approved.json +1047 -0
  44. data/spec/fixtures/approvals/facebookads_adaccount/ad_images/lists_images.approved.json +11 -0
  45. data/spec/fixtures/approvals/facebookads_adaccount/ad_sets/lists_ad_sets.approved.json +3 -0
  46. data/spec/fixtures/approvals/facebookads_adaccount/ads/lists_ads.approved.json +3 -0
  47. data/spec/fixtures/approvals/facebookads_adaccount/all/lists_all_accounts.approved.json +92 -0
  48. data/spec/fixtures/approvals/facebookads_adaccount/create_ad_campaign/creates_a_new_ad_campaign.approved.json +13 -0
  49. data/spec/fixtures/approvals/facebookads_adaccount/create_ad_images/creates_an_image.approved.json +11 -0
  50. data/spec/fixtures/approvals/facebookads_adaccount/find_by/finds_a_specific_account.approved.json +9 -0
  51. data/spec/fixtures/approvals/facebookads_adaccount/reach_estimate/estimates_the_reach_of_a_targeting_spec.approved.json +358 -0
  52. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_campaigns/lists_campaigns.yml +56 -0
  53. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_creatives/lists_creatives.yml +91 -0
  54. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_images/lists_images.yml +56 -0
  55. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_sets/lists_ad_sets.yml +56 -0
  56. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ads/lists_ads.yml +56 -0
  57. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_all/lists_all_accounts.yml +58 -0
  58. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_create_ad_campaign/creates_a_new_ad_campaign.yml +115 -0
  59. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_create_ad_images/creates_an_image.yml +2865 -0
  60. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_find_by/finds_a_specific_account.yml +58 -0
  61. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_reach_estimate/estimates_the_reach_of_a_targeting_spec.yml +56 -0
  62. data/spec/fixtures/cassettes/FacebookAds_AdCampaign/_destroy/creates_a_new_ad_campaign.yml +164 -0
  63. data/spec/spec_helper.rb +7 -0
  64. data/spec/support/approvals.rb +10 -0
  65. data/spec/support/facebook_ads.rb +4 -0
  66. data/spec/support/rest_client.rb +13 -0
  67. data/spec/support/vcr.rb +16 -0
  68. metadata +47 -29
  69. data/test/ad_account_test.rb +0 -27
  70. data/test/ad_campaign_test.rb +0 -32
  71. data/test/ad_creative_test.rb +0 -7
  72. data/test/ad_image_test.rb +0 -27
  73. data/test/ad_insight_test.rb +0 -7
  74. data/test/ad_product_catalog_test.rb +0 -28
  75. data/test/ad_product_feed_test.rb +0 -7
  76. data/test/ad_product_set_test.rb +0 -7
  77. data/test/ad_product_test.rb +0 -22
  78. data/test/ad_set_test.rb +0 -48
  79. data/test/ad_targeting_test.rb +0 -7
  80. data/test/ad_test.rb +0 -7
  81. data/test/facebook_ads_test.rb +0 -8
  82. data/test/test_helper.rb +0 -64
  83. data/test/vcr_cassettes/AdAccountTest-test_all.yml +0 -70
  84. data/test/vcr_cassettes/AdAccountTest-test_applications.yml +0 -130
  85. data/test/vcr_cassettes/AdAccountTest-test_find_by.yml +0 -71
  86. data/test/vcr_cassettes/AdCampaignTest-test_create.yml +0 -295
  87. data/test/vcr_cassettes/AdCampaignTest-test_list.yml +0 -133
  88. data/test/vcr_cassettes/AdImageTest-test_create.yml +0 -2963
  89. data/test/vcr_cassettes/AdImageTest-test_list.yml +0 -137
  90. data/test/vcr_cassettes/AdProductCatalogTest-test_all.yml +0 -60
  91. data/test/vcr_cassettes/AdProductCatalogTest-test_create.yml +0 -256
  92. data/test/vcr_cassettes/AdProductTest-test_list.yml +0 -130
  93. data/test/vcr_cassettes/AdSetTest-test_create.yml +0 -189
  94. data/test/vcr_cassettes/AdSetTest-test_destroy.yml +0 -124
  95. data/test/vcr_cassettes/AdSetTest-test_update.yml +0 -134
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf22df6e62e386f9fcdb2f9e7d9be3edafb0ff7d
4
- data.tar.gz: 0327f5a21d3963224a14c2b429eb9be040476e93
3
+ metadata.gz: 62ff9dd5a06adb1dd35f8ac42de0c0ad2cfed483
4
+ data.tar.gz: ca66b643ff764379230f2a9aae554d24b38220c1
5
5
  SHA512:
6
- metadata.gz: b834ddb9ab674ad353d74171ea3ad90822ac1298b50a2b83d4f62595d93b6738c234736a98a70f823a9df0cd86dadadfa113c24544ee7e770b268a9a40da2be5
7
- data.tar.gz: d7027a82225878643cb3f1de1dee0c744cf1a6122412114fc5a752ea07fc1c4831e4d555f5f5f749746a45a109e5a6a0902df375ebc50ee409316f3774bca72f
6
+ metadata.gz: 5d66eb00859e9faf05c806fb885d4ffe9da2d8d55930974f1a44d4748f4e0ac2950f019091a61c92efd7af80600e01f720d9b4316934c73460fb4065a2a96600
7
+ data.tar.gz: a18712eb4d1a844ab96ea041d30b072e5b2b6ea792564669ed341e2609befbe5a5abdde56b960a1bf58021a0fa37280f7dc62eb410e9b3fa2eee8a0c6aba93ea
data/.approvals ADDED
File without changes
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -1,3 +1,5 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  AllCops:
2
4
  Exclude:
3
5
  - bin/console
@@ -9,15 +11,25 @@ Metrics/CyclomaticComplexity:
9
11
  Enabled: false
10
12
  Metrics/PerceivedComplexity:
11
13
  Enabled: false
12
-
13
14
  Metrics/LineLength:
14
15
  Enabled: false
15
16
  Metrics/ClassLength:
16
17
  Enabled: false
17
18
  Metrics/MethodLength:
18
19
  Enabled: false
20
+ Metrics/BlockLength:
21
+ Enabled: false
19
22
  Metrics/ParameterLists:
20
23
  Enabled: false
21
24
 
22
25
  Style/Documentation:
23
26
  Enabled: false
27
+ Style/IndentationWidth:
28
+ Enabled: false
29
+ Style/ElseAlignment:
30
+ Enabled: false
31
+ Style/GuardClause:
32
+ Enabled: false
33
+
34
+ # Lint/EndAlignment:
35
+ # Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,16 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2017-04-25 18:21:46 -0700 using RuboCop version 0.48.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ # Cop supports --auto-correct.
11
+ # Configuration parameters: EnforcedStyleAlignWith, SupportedStylesAlignWith, AutoCorrect.
12
+ # SupportedStylesAlignWith: keyword, variable, start_of_line
13
+ Lint/EndAlignment:
14
+ Exclude:
15
+ - 'lib/facebook_ads/ad_account.rb'
16
+ - 'lib/facebook_ads/base.rb'
data/.travis.yml CHANGED
@@ -4,5 +4,7 @@ rvm:
4
4
  branches:
5
5
  only:
6
6
  - master
7
+ script:
8
+ # - bundle exec rubocop
9
+ - bundle exec rspec
7
10
  cache: bundler
8
- script: bundle exec rake test
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## 0.1.12 (2017-05-25)
2
+ - Added complete set of ad campaign objectives. (#9, @cte)
3
+ - Switched to rspec from minitest. (#8, @cte)
4
+ - Formatting tweaks in exception error messages (#7, @dekaikiwi)
5
+ - Added a reach_estimate method for ad accounts (ae35878, @cte)
data/Gemfile CHANGED
@@ -1,15 +1,18 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
- group :development do
5
- gem 'pry', '~> 0.10'
6
- gem 'awesome_print', '~> 1.7'
4
+ group :development, :test do
5
+ gem 'awesome_print'
6
+ gem 'pry'
7
+ gem 'rake'
8
+ gem 'rubocop'
7
9
  end
8
10
 
9
11
  group :test do
10
- gem 'rake'
11
- gem 'minitest'
12
- gem 'webmock'
13
- gem 'vcr'
12
+ gem 'approvals'
14
13
  gem 'coveralls', require: false
14
+ gem 'multi_json'
15
+ gem 'rspec'
16
+ gem 'vcr'
17
+ gem 'webmock'
15
18
  end
data/Gemfile.lock CHANGED
@@ -8,58 +8,92 @@ PATH
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- addressable (2.5.0)
11
+ addressable (2.5.1)
12
12
  public_suffix (~> 2.0, >= 2.0.2)
13
+ approvals (0.0.22)
14
+ nokogiri (~> 1.6)
15
+ thor (~> 0.18)
16
+ ast (2.3.0)
13
17
  awesome_print (1.7.0)
14
18
  coderay (1.1.1)
15
- coveralls (0.8.17)
19
+ coveralls (0.8.20)
16
20
  json (>= 1.8, < 3)
17
- simplecov (~> 0.12.0)
21
+ simplecov (~> 0.14.1)
18
22
  term-ansicolor (~> 1.3)
19
- thor (~> 0.19.1)
23
+ thor (~> 0.19.4)
20
24
  tins (~> 1.6)
21
25
  crack (0.4.3)
22
26
  safe_yaml (~> 1.0.0)
27
+ diff-lcs (1.3)
23
28
  docile (1.1.5)
24
- domain_name (0.5.20161129)
29
+ domain_name (0.5.20170404)
25
30
  unf (>= 0.0.5, < 1.0.0)
26
31
  hashdiff (0.3.2)
27
- hashie (3.4.6)
32
+ hashie (3.5.5)
28
33
  http-cookie (1.0.3)
29
34
  domain_name (~> 0.5)
30
- json (2.0.2)
35
+ json (2.1.0)
31
36
  method_source (0.8.2)
32
37
  mime-types (3.1)
33
38
  mime-types-data (~> 3.2015)
34
39
  mime-types-data (3.2016.0521)
35
- minitest (5.10.1)
40
+ mini_portile2 (2.1.0)
41
+ multi_json (1.12.1)
36
42
  netrc (0.11.0)
43
+ nokogiri (1.7.1)
44
+ mini_portile2 (~> 2.1.0)
45
+ parser (2.4.0.0)
46
+ ast (~> 2.2)
47
+ powerpack (0.1.1)
37
48
  pry (0.10.4)
38
49
  coderay (~> 1.1.0)
39
50
  method_source (~> 0.8.1)
40
51
  slop (~> 3.4)
41
- public_suffix (2.0.4)
52
+ public_suffix (2.0.5)
53
+ rainbow (2.2.2)
54
+ rake
42
55
  rake (12.0.0)
43
- rest-client (2.0.0)
56
+ rest-client (2.0.2)
44
57
  http-cookie (>= 1.0.2, < 2.0)
45
58
  mime-types (>= 1.16, < 4.0)
46
59
  netrc (~> 0.8)
60
+ rspec (3.5.0)
61
+ rspec-core (~> 3.5.0)
62
+ rspec-expectations (~> 3.5.0)
63
+ rspec-mocks (~> 3.5.0)
64
+ rspec-core (3.5.4)
65
+ rspec-support (~> 3.5.0)
66
+ rspec-expectations (3.5.0)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.5.0)
69
+ rspec-mocks (3.5.0)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.5.0)
72
+ rspec-support (3.5.0)
73
+ rubocop (0.48.1)
74
+ parser (>= 2.3.3.1, < 3.0)
75
+ powerpack (~> 0.1)
76
+ rainbow (>= 1.99.1, < 3.0)
77
+ ruby-progressbar (~> 1.7)
78
+ unicode-display_width (~> 1.0, >= 1.0.1)
79
+ ruby-progressbar (1.8.1)
47
80
  safe_yaml (1.0.4)
48
- simplecov (0.12.0)
81
+ simplecov (0.14.1)
49
82
  docile (~> 1.1.0)
50
83
  json (>= 1.8, < 3)
51
84
  simplecov-html (~> 0.10.0)
52
85
  simplecov-html (0.10.0)
53
86
  slop (3.6.0)
54
- term-ansicolor (1.4.0)
87
+ term-ansicolor (1.6.0)
55
88
  tins (~> 1.0)
56
89
  thor (0.19.4)
57
- tins (1.13.0)
90
+ tins (1.13.2)
58
91
  unf (0.1.4)
59
92
  unf_ext
60
- unf_ext (0.0.7.2)
93
+ unf_ext (0.0.7.4)
94
+ unicode-display_width (1.2.1)
61
95
  vcr (3.0.3)
62
- webmock (2.3.1)
96
+ webmock (3.0.1)
63
97
  addressable (>= 2.3.6)
64
98
  crack (>= 0.3.2)
65
99
  hashdiff
@@ -68,14 +102,17 @@ PLATFORMS
68
102
  ruby
69
103
 
70
104
  DEPENDENCIES
71
- awesome_print (~> 1.7)
105
+ approvals
106
+ awesome_print
72
107
  coveralls
73
108
  facebook_ads!
74
- minitest
75
- pry (~> 0.10)
109
+ multi_json
110
+ pry
76
111
  rake
112
+ rspec
113
+ rubocop
77
114
  vcr
78
115
  webmock
79
116
 
80
117
  BUNDLED WITH
81
- 1.13.7
118
+ 1.14.6
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Tophatter, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md CHANGED
@@ -28,6 +28,14 @@ You'll need an [Access Token](https://developers.facebook.com/docs/marketing-api
28
28
  FacebookAds.access_token = '[YOUR_ACCESS_TOKEN]'
29
29
  ```
30
30
 
31
+ ## API Version
32
+
33
+ This gem currently uses v2.8 of the Marketing API (soon to be updated to 2.9). You can change the version as desired with the following:
34
+
35
+ ```ruby
36
+ FacebookAds.base_uri = 'https://graph.facebook.com/v2.9'
37
+ ```
38
+
31
39
  ## Console
32
40
 
33
41
  This gem provides a console using [Pry](https://github.com/pry/pry) and [AwesomePrint](https://github.com/awesome-print/awesome_print) for you to test & debug.
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.11.gem
3
+ # gem push facebook_ads-0.1.12.gem
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'facebook_ads'
6
- s.version = '0.1.11'
6
+ s.version = '0.1.12'
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.licenses = ['MIT']
9
9
  s.authors = ['Chris Estreich']
@@ -2,8 +2,8 @@ module FacebookAds
2
2
  # An ad belongs to an ad set. It is created using an ad creative.
3
3
  # https://developers.facebook.com/docs/marketing-api/reference/adgroup
4
4
  class Ad < Base
5
- FIELDS = %w(id account_id campaign_id adset_id adlabels bid_amount bid_info bid_type configured_status conversion_specs created_time creative effective_status last_updated_by_app_id name tracking_specs updated_time ad_review_feedback).freeze
6
- STATUSES = %w(ACTIVE PAUSED DELETED PENDING_REVIEW DISAPPROVED PREAPPROVED PENDING_BILLING_INFO CAMPAIGN_PAUSED ARCHIVED ADSET_PAUSED).freeze
5
+ FIELDS = %w[id account_id campaign_id adset_id adlabels bid_amount bid_info bid_type configured_status conversion_specs created_time creative effective_status last_updated_by_app_id name tracking_specs updated_time ad_review_feedback].freeze
6
+ STATUSES = %w[ACTIVE PAUSED DELETED PENDING_REVIEW DISAPPROVED PREAPPROVED PENDING_BILLING_INFO CAMPAIGN_PAUSED ARCHIVED ADSET_PAUSED].freeze
7
7
 
8
8
  # belongs_to ad_account
9
9
 
@@ -2,7 +2,7 @@ module FacebookAds
2
2
  # An ad account has many ad campaigns, ad images, and ad creatives.
3
3
  # https://developers.facebook.com/docs/marketing-api/reference/ad-account
4
4
  class AdAccount < Base
5
- FIELDS = %w(id account_id account_status age created_time currency name).freeze
5
+ FIELDS = %w[id account_id account_status age created_time currency name].freeze
6
6
 
7
7
  class << self
8
8
  def all(query = {})
@@ -25,15 +25,15 @@ module FacebookAds
25
25
  end
26
26
 
27
27
  def create_ad_campaign(name:, objective:, status: 'ACTIVE')
28
- raise Exception, "Objective must be one of: #{AdCampaign::OBJECTIVES.to_sentence}" unless AdCampaign::OBJECTIVES.include?(objective)
29
- raise Exception, "Status must be one of: #{AdCampaign::STATUSES.to_sentence}" unless AdCampaign::STATUSES.include?(status)
28
+ raise Exception, "Objective must be one of: #{AdCampaign::OBJECTIVES.join(', ')}" unless AdCampaign::OBJECTIVES.include?(objective)
29
+ raise Exception, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
30
30
  query = { name: name, objective: objective, status: status }
31
31
  result = AdCampaign.post("/#{id}/campaigns", query: query)
32
32
  AdCampaign.find(result['id'])
33
33
  end
34
34
 
35
35
  def create_dynamic_ad_campaign(name:, product_catalog_id:, status: 'ACTIVE')
36
- raise Exception, "Status must be one of: #{AdCampaign::STATUSES.to_sentence}" unless AdCampaign::STATUSES.include?(status)
36
+ raise Exception, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
37
37
  query = { name: name, objective: 'PRODUCT_CATALOG_SALES', status: status, promoted_object: { product_catalog_id: product_catalog_id } }
38
38
  result = AdCampaign.post("/#{id}/campaigns", query: query)
39
39
  AdCampaign.find(result['id'])
@@ -96,21 +96,43 @@ module FacebookAds
96
96
  end.flatten
97
97
  end
98
98
 
99
+ def reach_estimate(targeting:, optimization_goal:, currency: 'USD')
100
+ raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
101
+
102
+ if targeting.is_a?(AdTargeting)
103
+ if targeting.validate!
104
+ targeting = targeting.to_hash
105
+ else
106
+ raise Exception, 'The provided targeting spec is not valid.'
107
+ end
108
+ end
109
+
110
+ query = {
111
+ targeting_spec: targeting.to_json,
112
+ optimize_for: optimization_goal,
113
+ currency: currency
114
+ }
115
+ self.class.get("/#{id}/reachestimate", query: query, objectify: false)
116
+ end
117
+
99
118
  # has_many applications
100
119
 
101
120
  def applications
102
121
  self.class.get("/#{id}/advertisable_applications", objectify: false)
103
122
  end
104
123
 
105
- def create_ad_audience_with_pixel(name:, pixel_id:, event_name:)
124
+ # hash_many ad_audiences
125
+
126
+ def create_ad_audience_with_pixel(name:, pixel_id:, event_name:, subtype: 'WEBSITE', retention_days: 15)
106
127
  query = {
107
- name: name,
108
- pixel_id: pixel_id,
109
- subtype: 'WEBSITE',
110
- retention_days: 15,
111
- rule: { event: { i_contains: event_name } }.to_json,
112
- prefill: 1
113
- }
128
+ name: name,
129
+ pixel_id: pixel_id,
130
+ subtype: subtype,
131
+ retention_days: retention_days,
132
+ rule: { event: { i_contains: event_name } }.to_json,
133
+ prefill: 1
134
+ }
135
+
114
136
  result = AdAudience.post("/#{id}/customaudiences", query: query)
115
137
  AdAudience.find(result['id'])
116
138
  end
@@ -118,29 +140,40 @@ module FacebookAds
118
140
  private
119
141
 
120
142
  def create_carousel_ad_creative(creative)
121
- required = %i(name page_id link message assets call_to_action_type multi_share_optimized multi_share_end_card)
143
+ required = %i[name page_id link message assets call_to_action_type multi_share_optimized multi_share_end_card]
144
+
122
145
  unless (keys = required - creative.keys).length.zero?
123
- raise Exception, "Creative is missing the following: #{keys.to_sentence}"
146
+ raise Exception, "Creative is missing the following: #{keys.join(', ')}"
124
147
  end
125
148
 
126
- 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])
149
+ raise Exception, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.join(', ')}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
150
+
127
151
  query = if creative[:product_set_id].present?
128
- AdCreative.product_set(name: creative[:name], page_id: creative[:page_id], link: creative[:link], message: creative[:message], headline: creative[:headline], description: creative[:description], product_set_id: creative[:product_set_id])
152
+ AdCreative.product_set(
153
+ name: creative[:name],
154
+ page_id: creative[:page_id],
155
+ link: creative[:link],
156
+ message: creative[:message],
157
+ headline: creative[:headline],
158
+ description: creative[:description],
159
+ product_set_id: creative[:product_set_id]
160
+ )
129
161
  else
130
162
  AdCreative.carousel(creative)
131
163
  end
164
+
132
165
  result = AdCreative.post("/#{id}/adcreatives", query: query)
133
166
  AdCreative.find(result['id'])
134
167
  end
135
168
 
136
169
  def create_image_ad_creative(creative)
137
- required = %i(name page_id message link link_title image_hash call_to_action_type)
170
+ required = %i[name page_id message link link_title image_hash call_to_action_type]
138
171
 
139
172
  unless (keys = required - creative.keys).length.zero?
140
- raise Exception, "Creative is missing the following: #{keys.to_sentence}"
173
+ raise Exception, "Creative is missing the following: #{keys.join(', ')}"
141
174
  end
142
175
 
143
- 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])
176
+ raise Exception, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.join(', ')}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
144
177
  query = AdCreative.photo(creative)
145
178
  result = AdCreative.post("/#{id}/adcreatives", query: query)
146
179
  AdCreative.find(result['id'])
@@ -1,7 +1,7 @@
1
1
  module FacebookAds
2
2
  # https://developers.facebook.com/docs/marketing-api/reference/custom-audience
3
3
  class AdAudience < Base
4
- FIELDS = %w(id account_id subtype name description approximate_count data_source delivery_status external_event_source lookalike_audience_ids lookalike_spec operation_status opt_out_link permission_for_actions pixel_id retention_days rule time_content_updated time_created time_updated).freeze
4
+ FIELDS = %w[id account_id subtype name description approximate_count data_source delivery_status external_event_source lookalike_audience_ids lookalike_spec operation_status opt_out_link permission_for_actions pixel_id retention_days rule time_content_updated time_created time_updated].freeze
5
5
 
6
6
  # belongs_to ad_account
7
7