עדכונים באמצעות אנונימיזציה של שדות

ב-Google Ads API, העדכונים מתבצעים באמצעות מסכת שדות. מסכת השדות מפרטת את כל השדות שאתם מתכוונים לשנות באמצעות העדכון, וכל שדה שצוין ולא נמצא במסכת השדות לא נכלל, גם אם הוא נשלח לשרת.

FieldMaskUtil

הדרך המומלצת ליצור מסכות שדות היא באמצעות כלי השירות המובנה של מסכות שדות, שמסתיר פרטים ספציפיים ומאפשר ליצור מסכות שדות באופן אוטומטי על ידי מעקב אחרי השינויים שאתם מבצעים בשדות של הישות.

בדוגמה הבאה מוצג אופן יצירת מסכת שדות לעדכון קמפיין:

campaign = client.resource.campaign
campaign.resource_name = client.path.campaign(customer_id, campaign_id)

mask = client.field_mask.with campaign do
  campaign.status = :PAUSED
  campaign.network_settings = client.resource.network_settings do |ns|
    ns.target_search_network = false
  end
end

הקוד יוצר קודם אובייקט Campaign ריק, ואז מגדיר את שם המשאב שלו כדי לעדכן את ה-API לגבי הקמפיין שמתעדכן.

בדוגמה הזו נעשה שימוש בשיטה client.field_mask.with בקמפיין כדי להתחיל את הבלוק שכולל את העדכונים. בסוף הבלוק הזה, כלי השירות משווה בין המצב הנוכחי של הקמפיין אחרי הבלוק לבין המצב הראשוני של הקמפיין לפני הבלוק, ויוצר באופן אוטומטי מסכת שדות שמפרטת את השדות שהשתנו. אפשר לספק את מסכת השדה הזו לפעולה כשיוצרים אותה לקריאת mutate, באופן הבא:

operation = client.operation.campaign
operation.update = campaign
operation.update_mask = mask

השיטה הזו מומלצת כשבונים פעולה מורכבת ורוצים שליטה מדויקת בכל שלב. עם זאת, ברוב המקרים אפשר להעביר את שם המשאב (או מופע קיים של משאב) ל-factory method של ספריית Ruby:

campaign_resource_name = client.path.campaign(customer_id, campaign_id)

operation =
  client.operation.update_resource.campaign(campaign_resource_name) do |c|
    c.status = :PAUSED
    c.network_settings = client.resource.network_settings do |ns|
      ns.target_search_network = false
    end
  end

כשמזינים מחרוזת של שם משאב, השיטה הזו יוצרת באופן אוטומטי משאב קמפיין חדש עם resource_name מאוכלס, בונה את מסכת השדות על סמך השינויים שאתם מבצעים בתוך הבלוק, בונה את פעולת העדכון ומחזירה את הפעולה הסופית עם update ו-update_mask שכבר מאוכלסים. אפשר גם להעביר מופע פרוטו קיים של Campaign במקום מחרוזת של שם משאב כדי לציין את המצב ההתחלתי של הקמפיין. התבנית הזו מתאימה לכל המשאבים שתומכים בפעולת העדכון.

יצירה ידנית של מסכת שדות

כדי ליצור מסכת שדות מאפס בלי להשתמש בכלי עזר של ספרייה, יוצרים Google::Protobuf::FieldMask, יוצרים מערך עם השמות של כל השדות שרוצים לשנות, ומקצים את המערך לשדה paths של מסכת השדות:

mask = Google::Protobuf::FieldMask.new
mask.paths = ['status', 'name']

עדכון של שדות הודעה ושדות משנה שלהם

לשדות MESSAGE יכולים להיות שדות משנה (כמו MaximizeConversions, שיש לו שלושה: target_cpa_micros,‏ cpc_bid_ceiling_micros ו-cpc_bid_floor_micros), או שלא יהיו להם שדות משנה בכלל (כמו ManualCpm).

שדות של הודעות ללא שדות משנה מוגדרים

כשמעדכנים שדה MESSAGE שלא מוגדרים בו שדות משנה, משתמשים ב-FieldMaskUtil כדי ליצור מסכת שדה, כמו שמוצג למעלה.

שדות של הודעות עם שדות משנה מוגדרים

כשמעדכנים שדה MESSAGE שמוגדר עם שדות משנה בלי להגדיר במפורש אף אחד משדות המשנה בהודעה הזו, צריך להוסיף באופן ידני כל אחד משדות המשנה הניתנים לשינוי של MESSAGE ל-FieldMask, בדומה לדוגמה הקודמת שבה נוצרה מסכת שדה מאפס.

דוגמה נפוצה אחת היא עדכון של שיטת הבידינג בקמפיין בלי להגדיר אף אחד מהשדות בשיטת הבידינג החדשה. בדוגמה הבאה מוצג איך לעדכן קמפיין כדי להשתמש בשיטת הבידינג MaximizeConversions בלי להגדיר אף אחד משדות המשנה בשיטת הבידינג.

בדוגמה הזו, שימוש בהשוואה המובנית של FieldMaskUtil לא משיג את המטרה הרצויה.

הקוד הבא יוצר מסכת שדות שכוללת את maximize_conversions. עם זאת, Google Ads API לא מאפשר התנהגות כזו כדי למנוע מחיקה מקרית של שדות, ומפיק שגיאה מסוג FieldMaskError.FIELD_HAS_SUBFIELDS.

# Creates a campaign with the proper resource name.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
end

# Update the maximize conversions field within the update block, so it's
# captured in the field mask.
operation = client.operation.update_resource.campaign(campaign) do |c|
  c.maximize_conversions = client.resource.maximize_conversions
end

# Sends the operation in a mutate request that results in a
# FieldMaskError.FIELD_HAS_SUBFIELDS error because empty MESSAGE fields cannot
# be included in a field mask.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation]
)
# Create the operation directly from the campaign's resource name. Don't do
# anything in the block so that the field mask starts empty. You can modify
# other fields in this block, except the message field intended to have a
# blank subfield.
campaign_resource_name = client.path.campaign(customer_id, campaign_id)
operation = client.operation.update_resource.campaign(campaign_resource_name) {}

# Manually add the maximize conversions subfield to the field mask so the API
# knows to clear it.
operation.update_mask.paths << 'maximize_conversions.target_cpa_micros'

# This operation succeeds.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation]
)

ניקוי השדות

אפשר לנקות שדות מסוימים באופן מפורש. בדומה לדוגמה הקודמת, צריך להוסיף את השדות האלה באופן מפורש למסכת השדות. לדוגמה, נניח שיש לכם קמפיין שמוגדרת בו שיטת בידינג MaximizeConversions, ושדה target_cpa_micros מוגדר עם ערך שגדול מ-0.

ב-proto3, הגדרה של שדה סקלרי שאינו אופציונלי לערך ברירת המחדל שלו (0) לא ניתנת להבחנה מהשארת השדה לא מוגדר במופע חדש של הודעה. כתוצאה מכך, FieldMaskUtil מוסיף את maximize_conversions למסכת השדות במקום את maximize_conversions.target_cpa_micros, וזה גורם לשגיאה FieldMaskError.FIELD_HAS_SUBFIELDS.

# Create a campaign object representing the campaign you want to change.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
end

# The field mask in this operation includes 'maximize_conversions',
# but not 'maximize_conversions.target_cpa_micros', so it results in an
# error.
operation = client.operation.update_resource.campaign(campaign) do |c|
  c.maximize_conversions = client.resource.maximize_conversions do |mc|
    mc.target_cpa_micros = 0
  end
end

# Operation fails because the field mask is invalid.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation]
)
# Create a campaign including the maximize conversions fields right away, since
# they are manually added to the field mask.
campaign = client.resource.campaign do |c|
  c.resource_name = client.path.campaign(customer_id, campaign_id)
  c.maximize_conversions = client.resource.maximize_conversions do |mc|
    mc.target_cpa_micros = 0
  end
end

# Create the operation with an empty field mask. You can add a block here with
# other changes that are automatically added to the field mask.
operation = client.operation.update_resource.campaign(campaign) {}

# Add the field to the field mask so the API knows to clear it.
operation.update_mask.paths << 'maximize_conversions.target_cpa_micros'

# Operation succeeds because the correct field mask is specified.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation]
)

שימו לב שגישת ההשוואה האוטומטית פועלת כצפוי בשדות שמוגדרים כ-optional במאגרי אחסון לפרוטוקולים של Google Ads API. מכיוון ש-target_cpa_micros הוא לא שדה optional ב-MaximizeConversions, צריך להוסיף במפורש את הנתיב ל-update_mask.paths כדי לנקות אותו.