В 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
Этот метод рекомендуется использовать, если вы создаете сложную операцию и хотите контролировать каждый шаг. Однако в большинстве случаев вы можете передать название ресурса (или существующий экземпляр ресурса) в метод фабрики библиотеки 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.