Actualizaciones con máscaras de campo

En la API de Google Ads, las actualizaciones se realizan mediante una máscara de campo. La máscara de campo enumera todos los campos que deseas cambiar con la actualización y se ignorará cualquier campo especificado que no esté en la máscara de campo, incluso si se envía al servidor.

FieldMaskUtil

La forma recomendada de generar máscaras de campo es usar nuestra utilidad integrada de máscara de campo, que oculta muchos de los detalles específicos y te permite generar máscaras de campo automáticamente mediante la supervisión de los cambios que realices en los campos de la entidad.

A continuación, te mostramos cómo generar una máscara de campo para actualizar una campaña:

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

El código primero crea un objeto de campaña vacío y, luego, establece el nombre de su recurso para informar a la API sobre la campaña que se está actualizando.

En este ejemplo, se usa el método client.field_mask.with en la campaña para comenzar el bloque que incluye las actualizaciones. Al final de este bloque, la utilidad compara el estado actual de la campaña después del bloqueo con el estado inicial de la campaña antes del bloqueo y genera automáticamente una máscara de campo que enumera los campos modificados. Puedes proporcionar esa máscara de campo a la operación cuando la construyes para la llamada de mutación de la siguiente manera:

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

Se recomienda este método cuando realizas una operación complicada y deseas un control detallado de cada paso. Sin embargo, en la mayoría de los casos, puedes usar la utilidad más simple de la biblioteca de Ruby:

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

Este método crea automáticamente un nuevo recurso de campaña vacío, construye la máscara de campo según los cambios que realices en el bloque, compila la operación de actualización y muestra la operación final con update y update_mask ya propagados. También puedes pasar una campaña al método campaign para especificar el estado inicial de la campaña. Este patrón funciona para todos los recursos que admiten la operación de actualización.

Crea una máscara manualmente

Para crear una máscara de campo desde cero, sin usar ninguna utilidad de biblioteca, primero debes crear una Google::Protobuf::FieldMask, luego hacer un array con los nombres de todos los campos que deseas cambiar y, por último, asignar el array al campo path de la máscara de campo.

mask = Google::Protobuf::FieldMask.new
mask.path = ["status", "name"]

Actualiza los campos de mensaje y sus subcampos

Los campos MESSAGE pueden tener subcampos (como MaximizeConversions, que tiene tres: target_cpa_micros, cpc_bid_ceiling_micros y cpc_bid_floor_micros), o no pueden tener ninguno (como ManualCpm).

Campos de mensaje sin subcampos definidos

Cuando actualices un campo MESSAGE que no esté definido con ningún subcampo, usa FieldMaskUtil para generar una máscara de campo, como se presentó antes.

Campos de mensaje con subcampos definidos

Cuando actualizas un campo MESSAGE definido con subcampos sin configurar explícitamente ninguno de los subcampos de ese mensaje, debes agregar de forma manual cada uno de los subcampos MESSAGE mutables a FieldMask, similar al ejemplo anterior que creó una máscara de campo desde cero.

Un ejemplo común es actualizar la estrategia de ofertas de una campaña sin configurar ninguno de los campos de la estrategia de oferta nueva. En el siguiente ejemplo, se muestra cómo actualizar una campaña para usar la estrategia de ofertas MaximizeConversions sin configurar ninguno de los subcampos de la estrategia de ofertas.

Para este ejemplo, el uso de la comparación integrada de FieldMaskUtil no logra el objetivo previsto.

El siguiente código genera una máscara de campo que incluye maximize_conversions. Sin embargo, la API de Google Ads no permite este comportamiento para evitar que se borren campos por accidente y se produce un error 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 will result 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],
)

En el siguiente código, se muestra cómo actualizar correctamente una campaña para usar la estrategia de ofertas MaximizeConversions sin configurar ninguno de sus subcampos.

# Create the operation directly from the campaign's resource name. Don't do
# anything in the block so that the field mask is empty. You could modify other
# fields in this block, just not the message field that is intended to have a
# blank subfield. We'll add that below.
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],
)

Borrando campos

Algunos campos se pueden borrar de forma explícita. Al igual que en el ejemplo anterior, debes agregar de forma explícita estos campos a la máscara de campo. Por ejemplo, supongamos que tienes una campaña que utiliza la estrategia de ofertas MaximizeConversions y que el campo target_cpa_micros está configurado con un valor superior a 0.

Se ejecuta el siguiente código. Sin embargo, maximize_conversions.target_cpa_micros no se agregará a la máscara de campo, por lo que no se realizarán cambios en el campo target_cpa_micros:

# 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 will include 'maximize_conversions',
# but not 'maximize_conversions.target_cpa_micros', so it will result 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 will fail since field mask is incorrect.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
end

En el siguiente código, se muestra cómo borrar correctamente el campo target_cpa_micros de la estrategia de ofertas MaximizeConversions.

# Create a campaign including the maximize conversions fields right away, since
# we're going to manually add them 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 may add a block here with
# other changes that will automatically get 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 will succeed since we specified the correct field mask.
response = client.service.campaign.mutate_campaigns(
  customer_id: customer_id,
  operations: [operation],
end

Ten en cuenta que el código "incorrecto" funciona según lo previsto para los campos que se definen como optional en la API de Google Ads protocol buffers. Sin embargo, como target_cpa_micros no es un campo optional, el código "incorrecto" no actualiza la estrategia de oferta para borrar el campo target_cpa.