facebook_ads 0.6.6 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +27 -0
  3. data/.rubocop.yml +11 -10
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +30 -9
  7. data/Gemfile +2 -2
  8. data/LICENSE.md +1 -1
  9. data/README.md +4 -5
  10. data/bin/facebook_ads_console +1 -1
  11. data/facebook_ads.gemspec +4 -5
  12. data/lib/facebook_ads.rb +71 -5
  13. data/lib/facebook_ads/ad.rb +2 -2
  14. data/lib/facebook_ads/ad_account.rb +18 -23
  15. data/lib/facebook_ads/ad_audience.rb +7 -7
  16. data/lib/facebook_ads/ad_campaign.rb +7 -7
  17. data/lib/facebook_ads/ad_creative.rb +3 -3
  18. data/lib/facebook_ads/ad_exception.rb +1 -0
  19. data/lib/facebook_ads/ad_image.rb +2 -2
  20. data/lib/facebook_ads/ad_insight.rb +5 -5
  21. data/lib/facebook_ads/ad_set.rb +5 -2
  22. data/lib/facebook_ads/ad_targeting.rb +2 -4
  23. data/lib/facebook_ads/base.rb +9 -16
  24. data/spec/facebook_ads/ad_account_spec.rb +16 -13
  25. data/spec/facebook_ads/ad_campaign_spec.rb +0 -3
  26. data/spec/facebook_ads/facebook_ads_spec.rb +50 -10
  27. data/spec/fixtures/cassettes/FacebookAds/_stubbornly_get/executes_the_request_for_the_provided_url.yml +63 -0
  28. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_creatives/lists_creatives.yml +1 -1
  29. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_sets/lists_ad_sets.yml +1 -1
  30. data/spec/fixtures/cassettes/FacebookAds_AdAccount/_create_ad_creative/creates_carousel_ad_creative.yml +7 -7
  31. data/spec/fixtures/cassettes/FacebookAds_AdCampaign/_create_ad_set/creates_valid_ad_set.yml +3 -3
  32. data/spec/spec_helper.rb +1 -4
  33. data/spec/support/rest_client.rb +1 -1
  34. metadata +21 -39
  35. data/.coveralls.yml +0 -1
  36. data/.travis.yml +0 -7
  37. data/spec/facebook_ads/ad_creative_spec.rb +0 -6
  38. data/spec/facebook_ads/ad_image_spec.rb +0 -6
  39. data/spec/facebook_ads/ad_insight_spec.rb +0 -6
  40. data/spec/facebook_ads/ad_product_catalog_spec.rb +0 -29
  41. data/spec/facebook_ads/ad_product_feed_spec.rb +0 -6
  42. data/spec/facebook_ads/ad_product_set_spec.rb +0 -6
  43. data/spec/facebook_ads/ad_product_spec.rb +0 -23
  44. data/spec/facebook_ads/ad_set_activity_spec.rb +0 -6
  45. data/spec/facebook_ads/ad_set_spec.rb +0 -49
  46. data/spec/facebook_ads/ad_spec.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e3af59459c263bb4fa49981b02306356052e2be4
4
- data.tar.gz: 8475d3922f3ba087e45259c4f7a27ed75c02af23
2
+ SHA256:
3
+ metadata.gz: 5a7277800ac2a81f155ef378e2f5a0b78a85cf00c284ccb18c521b0288d6d467
4
+ data.tar.gz: 603886d3c551084d3b317fa18a0f55a9992113a7a29ae78bd8036490d56bd18c
5
5
  SHA512:
6
- metadata.gz: 3869ae0fe2d04ede54ebe60459c23ca2bf20c48314b6e747c35806231cdb772c9f8c05338782cac1a3d1bb94431d41f4a3815c28b64e1dc5a320bede55225069
7
- data.tar.gz: 7de25dfeccc8c06be316c301b38c35332f99a46f7b68708296b05f073f18e92e18114b3208cf2e357964880b3fdef4a0d8ffbdbc694429ba781a1f5399359be4
6
+ metadata.gz: c943be4095453ed6ef0da92ec2c8b1e542c92e0f10d898c958855f593e857c769697a36b0d0a6b168f8fa6ef7c47f616b84418807c0916b5dda447665130751b
7
+ data.tar.gz: 0ccc1ad73365c2791e1a58329265964d18c6af52fb1ffe85d3d95314971f3802ca716a2d6ca5403b7874882922ca2f2fe55c53104d9199f9e91ef1618489ad1c
@@ -0,0 +1,27 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ aws-cli: circleci/aws-cli@1.2.1
5
+ ruby: circleci/ruby@1.1.0
6
+
7
+ jobs:
8
+ test:
9
+ docker:
10
+ - image: circleci/ruby:2.7.0-node
11
+ executor: ruby/default
12
+ working_directory: ~/repo
13
+ environment:
14
+ APP_BUNDLER_VERSION: '2.1.2'
15
+ steps:
16
+ - checkout:
17
+ path: ~/repo
18
+ - ruby/install-deps:
19
+ with-cache: false
20
+ - ruby/rspec-test
21
+ - ruby/rubocop-check
22
+
23
+ workflows:
24
+ version: 2
25
+ build:
26
+ jobs:
27
+ - test
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.3
2
+ TargetRubyVersion: 2.5
3
+ NewCops: enable
3
4
 
4
5
  Metrics/AbcSize:
5
6
  Enabled: false
@@ -7,9 +8,6 @@ Metrics/CyclomaticComplexity:
7
8
  Enabled: false
8
9
  Metrics/PerceivedComplexity:
9
10
  Enabled: false
10
-
11
- Metrics/LineLength:
12
- Enabled: false
13
11
  Metrics/ClassLength:
14
12
  Enabled: false
15
13
  Metrics/MethodLength:
@@ -19,15 +17,18 @@ Metrics/BlockLength:
19
17
  Metrics/ParameterLists:
20
18
  Enabled: false
21
19
 
22
- Lint/EndAlignment:
20
+ Layout/ElseAlignment:
23
21
  Enabled: false
24
-
25
- Layout/IndentationWidth:
22
+ Layout/EndAlignment:
26
23
  Enabled: false
27
- Layout/ElseAlignment:
24
+ Layout/RescueEnsureAlignment:
25
+ Enabled: false
26
+ Layout/EmptyLineAfterGuardClause:
27
+ Enabled: false
28
+ Layout/LineLength:
29
+ Enabled: false
30
+ Layout/IndentationWidth:
28
31
  Enabled: false
29
32
 
30
33
  Style/Documentation:
31
34
  Enabled: false
32
- Style/GuardClause:
33
- Enabled: false
@@ -0,0 +1 @@
1
+ facebook-ruby-ads-sdk
@@ -0,0 +1 @@
1
+ 2.7.0
@@ -1,27 +1,48 @@
1
+ ## 0.7.0 (2020-09-29)
2
+ - Add stubborn network call helpers.
3
+ - Update default version to v7.0.
4
+ - Switch from TravisCI to CircleCI.
5
+ - Remove coveralls.
6
+ - Require ruby 2.5+.
7
+ - Update Rubocop & fix warnings.
8
+
9
+ ## 0.6.11 (2020-02-28)
10
+ - Fixed memoization in `FacebookAds::Ad`.
11
+
12
+ ## 0.6.10 (2019-05-06)
13
+ - Set default version to 3.2.
14
+ - Removed `relevance_score` from the list of default fields in `AdInsight`.
15
+
16
+ ## 0.6.9 (2019-03-25)
17
+ - Added the following fields to `AdCreative`: `product_set_id` and `url_tags`. (#37, @cte)
18
+
19
+ ## 0.6.7 (2019-03-07)
20
+ - Added the following fields to `AdSet`: `attribution_spec`, `start_time` and `end_time`. (#36, @cte)
21
+
1
22
  ## 0.6.6 (2018-11-29)
2
- - Added ability to pass date range when fetching `ad_set_activities`.
23
+ - Added ability to pass date range when fetching `ad_set_activities`. (#34, @amosharrafa)
3
24
 
4
25
  ## 0.6.5 (2018-11-26)
5
- - Expose `ad_set_activities` for `ad_sets`.
26
+ - Expose `ad_set_activities` for `ad_sets`. (#31, @amosharrafa)
6
27
 
7
28
  ## 0.6.4 (2018-10-03)
8
- - Expose `budget_remaining`, `daily_budget`, `lifetime_budget` for Ad Campaigns. These are needed when we have budgets at the Ad Campaign level and not at the Ad Set level.
29
+ - Expose `budget_remaining`, `daily_budget`, `lifetime_budget` for the `AdCampaign` object. You now have the option to set the budget ad the campaign level instead of the ad set level.
9
30
 
10
31
  ## 0.6.3 (2018-05-17)
11
- - Replaced deprecated `is_autobid` with new `bid_strategy` field
32
+ - Replaced deprecated `is_autobid` with new `bid_strategy` field.
12
33
 
13
34
  ## 0.6.2 (2018-05-08)
14
- - Set Product Catalog path to `/owned_product_catalogs` for API v2.11 compatibility
35
+ - Set Product Catalog path to `/owned_product_catalogs` for API v2.11 compatibility.
15
36
 
16
37
  ## 0.4 (2017-07-25)
17
- - Added ability to pass `bid_amount` parameter when creating ad sets
18
- - Ad Set `is_autobid` parameter now defaults to `nil` rather than `true`
38
+ - Added ability to pass `bid_amount` parameter when creating ad sets.
39
+ - Ad Set `is_autobid` parameter now defaults to `nil` rather than `true`.
19
40
 
20
41
  ## 0.3 (2017-07-24)
21
- - Added ability to pass `app_link` parameter with ad creatives
42
+ - Added ability to pass `app_link` parameter with ad creatives.
22
43
 
23
44
  ## 0.2 (2017-07-20)
24
- - Added ability to configure App Secret to be included with API requests
45
+ - Added ability to configure App Secret to be included with API requests.
25
46
 
26
47
  ## 0.1.12 (2017-05-25)
27
48
  - Added complete set of ad campaign objectives. (#9, @cte)
data/Gemfile CHANGED
@@ -7,14 +7,14 @@ group :development, :test do
7
7
  gem 'awesome_print'
8
8
  gem 'pry'
9
9
  gem 'rake'
10
- gem 'rubocop', '0.49.1'
10
+ gem 'rubocop'
11
11
  end
12
12
 
13
13
  group :test do
14
14
  gem 'approvals'
15
- gem 'coveralls', require: false
16
15
  gem 'multi_json'
17
16
  gem 'rspec'
17
+ gem 'rspec_junit_formatter'
18
18
  gem 'vcr'
19
19
  gem 'webmock'
20
20
  end
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017 Tophatter, Inc.
3
+ Copyright (c) 2020 Tophatter, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/facebook_ads.svg)](https://badge.fury.io/rb/facebook_ads)
2
- [![Build Status](https://travis-ci.org/tophatter/facebook-ruby-ads-sdk.svg?branch=master)](https://travis-ci.org/tophatter/facebook-ruby-ads-sdk)
3
- [![Coverage Status](https://coveralls.io/repos/github/tophatter/facebook-ruby-ads-sdk/badge.svg?branch=master)](https://coveralls.io/github/tophatter/facebook-ruby-ads-sdk?branch=master)
2
+ [![Build Status](https://circleci.com/gh/tophatter/facebook-ruby-ads-sdk.svg?style=svg&circle-token=3fa538bc2aece310fdc07b82ce77d117758afb02)](https://circleci.com/gh/tophatter/facebook-ruby-ads-sdk)
4
3
 
5
4
  # [Facebook Marketing API](https://developers.facebook.com/docs/marketing-apis) SDK for Ruby
6
5
 
@@ -17,7 +16,7 @@ gem install facebook_ads
17
16
  Or, add the following to your Gemfile:
18
17
 
19
18
  ```ruby
20
- gem 'facebook_ads', '~> 0.1'
19
+ gem 'facebook_ads', '~> 0.7'
21
20
  ```
22
21
 
23
22
  ## Permissions
@@ -36,10 +35,10 @@ FacebookAds.app_secret = '[YOUR_APP_SECRET]'
36
35
 
37
36
  ## API Version
38
37
 
39
- This gem currently uses v2.9 of the Marketing API (2.10 is released as of 7/18/2017). You can change the version as desired with the following:
38
+ This gem currently defaults v3.2 of the Marketing API. You can change the version as desired with the following:
40
39
 
41
40
  ```ruby
42
- FacebookAds.base_uri = 'https://graph.facebook.com/v2.10'
41
+ FacebookAds.base_uri = 'https://graph.facebook.com/[desired-version-here]'
43
42
  ```
44
43
 
45
44
  ## Console
@@ -19,7 +19,7 @@ rescue Errno::ENOENT
19
19
  puts 'Create a test_business_id file and add your Business ID to it.'
20
20
  end
21
21
 
22
- FacebookAds.logger = Logger.new(STDOUT)
22
+ FacebookAds.logger = Logger.new($stdout)
23
23
  FacebookAds.logger.level = Logger::Severity::DEBUG
24
24
 
25
25
  require 'awesome_print'
@@ -1,12 +1,11 @@
1
- # -*- encoding: utf-8 -*-
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # To publish the next version:
5
4
  # gem build facebook_ads.gemspec
6
- # gem push facebook_ads-0.6.6.gem
5
+ # gem push facebook_ads-0.7.0.gem
7
6
  Gem::Specification.new do |s|
8
7
  s.name = 'facebook_ads'
9
- s.version = '0.6.6'
8
+ s.version = '0.7.0'
10
9
  s.platform = Gem::Platform::RUBY
11
10
  s.licenses = ['MIT']
12
11
  s.authors = ['Chris Estreich']
@@ -17,10 +16,10 @@ Gem::Specification.new do |s|
17
16
 
18
17
  s.extra_rdoc_files = ['README.md']
19
18
 
20
- s.required_ruby_version = '~> 2.0'
19
+ s.required_ruby_version = '>= 2.5'
21
20
 
21
+ s.add_dependency 'hashie'
22
22
  s.add_dependency 'rest-client', '>= 1.6'
23
- s.add_dependency 'hashie', '~> 3.4'
24
23
 
25
24
  s.files = `git ls-files`.split("\n")
26
25
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -9,10 +9,31 @@ require 'openssl'
9
9
 
10
10
  # Internal requires.
11
11
  require 'facebook_ads/base'
12
- Dir[File.expand_path('../facebook_ads/*.rb', __FILE__)].each { |f| require f }
12
+ require 'facebook_ads/account'
13
+ require 'facebook_ads/ad_account'
14
+ require 'facebook_ads/ad_audience'
15
+ require 'facebook_ads/ad_campaign'
16
+ require 'facebook_ads/ad_creative'
17
+ require 'facebook_ads/ad_exception'
18
+ require 'facebook_ads/ad_image'
19
+ require 'facebook_ads/ad_insight'
20
+ require 'facebook_ads/ad_product_catalog'
21
+ require 'facebook_ads/ad_product_feed'
22
+ require 'facebook_ads/ad_product'
23
+ require 'facebook_ads/ad_set_activity'
24
+ require 'facebook_ads/ad_set'
25
+ require 'facebook_ads/ad_targeting'
26
+ require 'facebook_ads/ad_user'
27
+ require 'facebook_ads/ad'
28
+ require 'facebook_ads/advertisable_application'
13
29
 
14
30
  # The primary namespace for this gem.
15
31
  module FacebookAds
32
+ REQUEST_HEADERS = { accept: :json, accept_encoding: :identity }.freeze
33
+ RETRYABLE_ERRORS = [RestClient::ExceptionWithResponse, Errno::ECONNRESET, Errno::ECONNREFUSED].freeze
34
+ RETRY_LIMIT = 10
35
+ RECOVERABLE_CODES = [1, 2, 2601].freeze
36
+
16
37
  def self.logger=(logger)
17
38
  @logger = logger
18
39
  end
@@ -31,17 +52,16 @@ module FacebookAds
31
52
  end
32
53
 
33
54
  def self.base_uri
34
- @base_uri = "https://graph.facebook.com/v#{api_version}" unless defined?(@base_uri)
35
- @base_uri
55
+ @base_uri ||= "https://graph.facebook.com/v#{api_version}"
36
56
  end
37
57
 
38
58
  def self.api_version=(api_version)
39
59
  @api_version = api_version
60
+ @base_uri = nil
40
61
  end
41
62
 
42
63
  def self.api_version
43
- @api_version = '3.1' unless defined?(@api_version)
44
- @api_version
64
+ @api_version ||= '7.0'
45
65
  end
46
66
 
47
67
  def self.access_token=(access_token)
@@ -71,4 +91,50 @@ module FacebookAds
71
91
  def self.business_id
72
92
  @business_id
73
93
  end
94
+
95
+ # Stubborn network calls.
96
+
97
+ def self.stubbornly(retry_limit: RETRY_LIMIT, recoverable_codes: RECOVERABLE_CODES, debug: false)
98
+ raise ArgumentError unless block_given?
99
+
100
+ response = nil
101
+ retry_count = 0
102
+
103
+ loop do
104
+ response = yield
105
+ break
106
+ rescue *RETRYABLE_ERRORS => e
107
+ if e.is_a?(RestClient::ExceptionWithResponse)
108
+ error = begin
109
+ JSON.parse(e.response)
110
+ rescue JSON::ParserError
111
+ nil
112
+ end
113
+
114
+ code = error&.[]('code')
115
+ raise e if code && !recoverable_codes.include?(code)
116
+ end
117
+
118
+ raise e if retry_count >= retry_limit
119
+
120
+ retry_count += 1
121
+ wait = (retry_count**2) + 15 + (rand(15) * (retry_count + 1))
122
+ puts "retry ##{retry_count} will start in #{wait}s" if debug
123
+ sleep wait
124
+ end
125
+
126
+ response
127
+ end
128
+
129
+ def self.stubbornly_get(url, retry_limit: RETRY_LIMIT, recoverable_codes: RECOVERABLE_CODES, debug: false)
130
+ stubbornly(retry_limit: retry_limit, recoverable_codes: recoverable_codes, debug: debug) do
131
+ RestClient.get(url, REQUEST_HEADERS)
132
+ end
133
+ end
134
+
135
+ def self.stubbornly_post(url, payload, retry_limit: RETRY_LIMIT, recoverable_codes: RECOVERABLE_CODES, debug: false)
136
+ stubbornly(retry_limit: retry_limit, recoverable_codes: recoverable_codes, debug: debug) do
137
+ RestClient.post(url, payload, REQUEST_HEADERS)
138
+ end
139
+ end
74
140
  end
@@ -10,13 +10,13 @@ module FacebookAds
10
10
  # belongs_to ad_account
11
11
 
12
12
  def ad_account
13
- @ad_set ||= AdAccount.find(account_id)
13
+ @ad_account ||= AdAccount.find(account_id)
14
14
  end
15
15
 
16
16
  # belongs_to ad_campaign
17
17
 
18
18
  def ad_campaign
19
- @ad_set ||= AdCampaign.find(campaign_id)
19
+ @ad_campaign ||= AdCampaign.find(campaign_id)
20
20
  end
21
21
 
22
22
  # belongs_to ad_set
@@ -30,15 +30,15 @@ module FacebookAds
30
30
  end
31
31
 
32
32
  def create_ad_campaign(name:, objective:, status: 'ACTIVE')
33
- raise Exception, "Objective must be one of: #{AdCampaign::OBJECTIVES.join(', ')}" unless AdCampaign::OBJECTIVES.include?(objective)
34
- raise Exception, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
33
+ raise ArgumentError, "Objective must be one of: #{AdCampaign::OBJECTIVES.join(', ')}" unless AdCampaign::OBJECTIVES.include?(objective)
34
+ raise ArgumentError, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
35
35
  query = { name: name, objective: objective, status: status }
36
36
  result = AdCampaign.post("/#{id}/campaigns", query: query)
37
37
  AdCampaign.find(result['id'])
38
38
  end
39
39
 
40
40
  def create_dynamic_ad_campaign(name:, product_catalog_id:, status: 'ACTIVE')
41
- raise Exception, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
41
+ raise ArgumentError, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
42
42
  query = { name: name, objective: 'PRODUCT_CATALOG_SALES', status: status, promoted_object: { product_catalog_id: product_catalog_id } }
43
43
  result = AdCampaign.post("/#{id}/campaigns", query: query)
44
44
  AdCampaign.find(result['id'])
@@ -73,7 +73,7 @@ module FacebookAds
73
73
  end.to_h
74
74
 
75
75
  response = AdImage.post("/#{id}/adimages", query: files)
76
- files.values.each { |file| File.delete(file.path) }
76
+ files.each_value { |file| File.delete(file.path) }
77
77
  !response['images'].nil? ? ad_images(hashes: response['images'].map { |_key, hash| hash['hash'] }) : []
78
78
  end
79
79
 
@@ -84,8 +84,9 @@ module FacebookAds
84
84
  end
85
85
 
86
86
  def create_ad_creative(creative, creative_type: nil, carousel: false)
87
- # Support old deprecated carousel param
87
+ # Support old deprecated carousel param.
88
88
  return create_carousel_ad_creative(creative) if carousel
89
+
89
90
  case creative_type
90
91
  when 'carousel'
91
92
  create_carousel_ad_creative(creative)
@@ -127,14 +128,11 @@ module FacebookAds
127
128
  end
128
129
 
129
130
  def reach_estimate(targeting:, optimization_goal:, currency: 'USD')
130
- raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
131
+ raise ArgumentError, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
131
132
 
132
133
  if targeting.is_a?(AdTargeting)
133
- if targeting.validate!
134
- targeting = targeting.to_hash
135
- else
136
- raise Exception, 'The provided targeting spec is not valid.'
137
- end
134
+ raise ArgumentError, 'The provided targeting spec is not valid.' unless targeting.validate!
135
+ targeting = targeting.to_hash
138
136
  end
139
137
 
140
138
  query = {
@@ -147,14 +145,11 @@ module FacebookAds
147
145
  end
148
146
 
149
147
  def delivery_estimate(targeting:, optimization_goal:, currency: 'USD')
150
- raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
148
+ raise ArgumentError, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
151
149
 
152
150
  if targeting.is_a?(AdTargeting)
153
- if targeting.validate!
154
- targeting = targeting.to_hash
155
- else
156
- raise Exception, 'The provided targeting spec is not valid.'
157
- end
151
+ raise ArgumentError, 'The provided targeting spec is not valid.' unless targeting.validate!
152
+ targeting = targeting.to_hash
158
153
  end
159
154
 
160
155
  query = {
@@ -172,12 +167,12 @@ module FacebookAds
172
167
  required = %i[name page_id link message assets call_to_action_type multi_share_optimized multi_share_end_card]
173
168
 
174
169
  unless (keys = required - creative.keys).length.zero?
175
- raise Exception, "Creative is missing the following: #{keys.join(', ')}"
170
+ raise ArgumentError, "Creative is missing the following: #{keys.join(', ')}"
176
171
  end
177
172
 
178
- 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])
173
+ raise ArgumentError, "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])
179
174
 
180
- query = if creative[:product_set_id].present?
175
+ query = if creative[:product_set_id]
181
176
  AdCreative.product_set(
182
177
  name: creative[:name],
183
178
  page_id: creative[:page_id],
@@ -199,10 +194,10 @@ module FacebookAds
199
194
  required = %i[name page_id message link link_title image_hash call_to_action_type]
200
195
 
201
196
  unless (keys = required - creative.keys).length.zero?
202
- raise Exception, "Creative is missing the following: #{keys.join(', ')}"
197
+ raise ArgumentError, "Creative is missing the following: #{keys.join(', ')}"
203
198
  end
204
199
 
205
- 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])
200
+ raise ArgumentError, "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])
206
201
  query = AdCreative.photo(creative)
207
202
  result = AdCreative.post("/#{id}/adcreatives", query: query)
208
203
  AdCreative.find(result['id'])
@@ -212,7 +207,7 @@ module FacebookAds
212
207
  required = %i[name title body object_url link_url image_hash page_id]
213
208
 
214
209
  unless (keys = required - creative.keys).length.zero?
215
- raise Exception, "Creative is missing the following: #{keys.join(', ')}"
210
+ raise ArgumentError, "Creative is missing the following: #{keys.join(', ')}"
216
211
  end
217
212
 
218
213
  query = AdCreative.link(creative)