In the Google Ads API, updates are done using a field mask. The field mask lists all the fields you intend to change with the update, and any specified fields that aren't in the field mask are ignored, even if sent to the server.
FieldMaskUtil
The recommended way to generate field masks is using our built-in field mask utility which hides a lot of the specific details and lets you generate field masks automatically by monitoring the changes you make to the entity's fields.
Here's how you could generate a field mask for updating a campaign:
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
The code first creates an empty Campaign object, then sets its resource name to inform the API of the campaign being updated.
This example uses the client.field_mask.with
method on the campaign to begin
the block encompassing the updates. At the end of this block, the utility
compares the current status of the campaign after the block with the initial
status of the campaign before the block, and automatically produces a field
mask enumerating the changed fields. You can provide that field mask to the
operation when constructing it for the mutate call as follows:
operation = client.operation.campaign
operation.update = campaign
operation.update_mask = mask
This method is recommended when you're making a complicated operation and want fine control over every step. However, for most cases, you can use the simpler Ruby library utility:
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
This method automatically creates a new empty campaign resource, constructs
the field mask based on changes you make within the block, builds the update
operation, and returns the final operation with update
and update_mask
already populated. You can also pass a campaign to the campaign
method to
specify the starting state of the campaign as well. This pattern works for all
resources that support the update operation.
Manually creating a mask
To create a field mask from scratch, without using any library utilities, you
would first create a Google::Protobuf::FieldMask
, then make an array
populated with the names of all the fields you intend to change, and finally
assign the array to the field mask's path
field.
mask = Google::Protobuf::FieldMask.new
mask.path = ["status", "name"]
Updating message fields and their subfields
MESSAGE
fields can have subfields (such as
MaximizeConversions
which has three:
target_cpa_micros
, cpc_bid_ceiling_micros
, and cpc_bid_floor_micros
), or
they can have none at all (such as ManualCpm
).
Message fields with no defined subfields
When updating a MESSAGE
field that is not defined with any subfields, use the
FieldMaskUtil to generate a field mask, as presented earlier.
Message fields with defined subfields
When updating a MESSAGE
field that is defined with subfields without
explicitly setting any of the subfields on that message, you must manually add
each of the mutable MESSAGE
subfields to the FieldMask
, similar to the
earlier example that created a field mask from scratch.
One common example is updating a campaign's bidding strategy without setting
any of the fields on the new bidding strategy. The following example
demonstrates how to update a campaign to use the
MaximizeConversions
bidding strategy
without setting any of the subfields on the bidding strategy.
For this example, using the built-in comparison of the FieldMaskUtil does not achieve the intended goal.
The following code generates a field mask that includes maximize_conversions
.
However, the Google Ads API doesn't allow this behavior in order to prevent
accidentally clearing fields and produces a
FieldMaskError.FIELD_HAS_SUBFIELDS
error.
# 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],
)
The following code demonstrates how to properly update a campaign to use the
MaximizeConversions
bidding strategy without setting any of its subfields.
# 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],
)
Clearing fields
Some fields can be explicitly cleared. Similar to the previous example, you must
explicitly add these fields to the field mask. For example, assume you have a
campaign that uses a MaximizeConversions
bidding strategy and that the
target_cpa_micros
field is set with a value that is greater than 0
.
The following code runs; however, the maximize_conversions.target_cpa_micros
won't be added to the field mask and so no changes are made to the
target_cpa_micros
field:
# 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
The following code demonstrates how to properly clear the target_cpa_micros
field on the MaximizeConversions
bidding strategy.
# 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
Note that the "incorrect" code does work as intended for fields that are defined
as optional
in the Google Ads API protocol buffers
. But since the
target_cpa_micros
is
not an optional
field, the "incorrect" code does not update the bidding
strategy to clear the target_cpa
field.