Cập nhật bằng mặt nạ cho trường

Trong Google Ads API, các bản cập nhật được thực hiện bằng cách sử dụng mặt nạ trường. Mặt nạ trường liệt kê tất cả các trường mà bạn dự định thay đổi bằng nội dung cập nhật và mọi trường được chỉ định không có trong mặt nạ trường đều bị bỏ qua, ngay cả khi được gửi đến máy chủ.

FieldMaskUtil

Bạn nên tạo mặt nạ trường bằng cách sử dụng tiện ích mặt nạ trường tích hợp sẵn. Tiện ích này sẽ ẩn các thông tin chi tiết cụ thể và cho phép bạn tự động tạo mặt nạ trường bằng cách theo dõi các thay đổi mà bạn thực hiện đối với các trường của thực thể.

Ví dụ sau đây cho thấy cách tạo mặt nạ trường để cập nhật một chiến dịch:

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

Trước tiên, mã này sẽ tạo một đối tượng Campaign trống, sau đó đặt tên tài nguyên của đối tượng này để thông báo cho API về chiến dịch đang được cập nhật.

Ví dụ này sử dụng phương thức client.field_mask.with trên chiến dịch để bắt đầu khối chứa các nội dung cập nhật. Khi kết thúc khối này, tiện ích sẽ so sánh trạng thái hiện tại của chiến dịch sau khối với trạng thái ban đầu của chiến dịch trước khối và tự động tạo một mặt nạ trường liệt kê các trường đã thay đổi. Bạn có thể cung cấp mặt nạ trường đó cho thao tác khi tạo mặt nạ trường cho lệnh gọi thay đổi như sau:

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

Bạn nên sử dụng phương thức này khi tạo một thao tác phức tạp và muốn kiểm soát chi tiết từng bước. Tuy nhiên, trong hầu hết các trường hợp, bạn có thể truyền tên tài nguyên (hoặc một thực thể tài nguyên hiện có) đến phương thức nhà máy của thư viện 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

Khi được cung cấp một chuỗi tên tài nguyên, phương thức này sẽ tự động tạo một tài nguyên chiến dịch mới có sẵn resource_name, tạo mặt nạ trường dựa trên các thay đổi mà bạn thực hiện trong khối, tạo thao tác cập nhật và trả về thao tác cuối cùng có sẵn update và update_mask. Bạn cũng có thể truyền một thực thể proto Campaign hiện có thay vì một chuỗi tên tài nguyên để chỉ định trạng thái bắt đầu của chiến dịch. Mẫu này hoạt động cho tất cả tài nguyên hỗ trợ thao tác cập nhật.

Tạo mặt nạ trường theo cách thủ công

Để tạo mặt nạ trường từ đầu mà không cần sử dụng các tiện ích thư viện, hãy tạo một Google::Protobuf::FieldMask, tạo một mảng chứa tên của tất cả các trường mà bạn định thay đổi, rồi chỉ định mảng đó cho trường paths của mặt nạ trường:

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

Cập nhật các trường thông báo và trường con của chúng

Trường MESSAGE có thể có các trường phụ (chẳng hạn như MaximizeConversions, có 3 trường phụ: target_cpa_micros, cpc_bid_ceiling_micros và cpc_bid_floor_micros) hoặc không có trường phụ nào (chẳng hạn như ManualCpm).

Trường thông báo không có trường con được xác định

Khi cập nhật một trường MESSAGE không được xác định bằng bất kỳ trường con nào, hãy sử dụng FieldMaskUtil để tạo mặt nạ trường, như đã trình bày ở trên.

Trường thông báo có các trường con được xác định

Khi cập nhật một trường MESSAGE được xác định bằng các trường con mà không đặt rõ ràng bất kỳ trường con nào trên thông báo đó, bạn phải thêm từng trường con MESSAGE có thể thay đổi vào FieldMask theo cách thủ công, tương tự như ví dụ trước đó đã tạo mặt nạ trường từ đầu.

Một ví dụ phổ biến là cập nhật chiến lược đặt giá thầu của chiến dịch mà không đặt bất kỳ trường nào trong chiến lược đặt giá thầu mới. Ví dụ sau đây minh hoạ cách cập nhật một chiến dịch để sử dụng chiến lược đặt giá thầu MaximizeConversions mà không cần đặt bất kỳ trường phụ nào trong chiến lược đặt giá thầu.

Trong ví dụ này, việc sử dụng phép so sánh tích hợp của FieldMaskUtil không đạt được mục tiêu dự kiến.

Đoạn mã sau đây tạo một mặt nạ trường bao gồm maximize_conversions. Tuy nhiên, Google Ads API không cho phép hành vi này để ngăn việc vô tình xoá các trường và tạo ra lỗi 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]
)

Xoá các trường

Bạn có thể xoá một số trường một cách rõ ràng. Tương tự như ví dụ trước, bạn phải thêm các trường này vào mặt nạ trường một cách rõ ràng. Ví dụ: giả sử bạn có một chiến dịch sử dụng chiến lược đặt giá thầu MaximizeConversions và trường target_cpa_micros được đặt giá trị lớn hơn 0.

Trong proto3, việc đặt trường vô hướng không bắt buộc thành giá trị mặc định (0) không khác gì việc không đặt giá trị cho trường đó trên một thực thể thông báo mới. Do đó, FieldMaskUtil thêm maximize_conversions vào mặt nạ trường thay vì maximize_conversions.target_cpa_micros, gây ra lỗi 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]
)

Xin lưu ý rằng phương pháp so sánh tự động hoạt động như dự kiến đối với các trường được xác định là optional trong vùng đệm giao thức của Google Ads API. Vì target_cpa_micros không phải là trường optional trên MaximizeConversions, nên bạn phải thêm rõ ràng đường dẫn vào update_mask.paths để xoá trường này.