필드 마스크를 사용한 업데이트

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 메서드를 사용하여 업데이트를 포함하는 블록을 시작합니다. 이 블록의 끝에서 유틸리티는 블록 이후의 캠페인 현재 상태를 블록 이전의 캠페인 초기 상태와 비교하고 변경된 필드를 열거하는 필드 마스크를 자동으로 생성합니다. 다음과 같이 변형 호출을 위해 구성할 때 해당 필드 마스크를 작업에 제공할 수 있습니다.

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.target_cpa_micros 대신 maximize_conversions를 필드 마스크에 추가하여 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]
)

자동 비교 접근 방식은 Google Ads API 프로토콜 버퍼에서 optional로 정의된 필드에 대해 의도한 대로 작동합니다. target_cpa_micros는 MaximizeConversions의 optional 필드가 아니므로 이를 지우려면 update_mask.paths에 경로를 명시적으로 추가해야 합니다.