Module: Basecamp::Services::CardsExtensions

Defined in:
lib/basecamp/services/cards_extensions.rb

Overview

Merge-safe update for cards, prepended onto the generated CardsService (see the on_load hook in basecamp.rb).

BC3 builds the card's update params as { due_on: nil }.merge(card_params) (+kanban/cards_controller.rb+), so any update whose body omits due_on erases the card's due date. A sparse PUT — the natural thing to write — is therefore destructive on the raw endpoint, which remains available as #update_verbatim.

update composes the public get and update_verbatim methods, so hooks observe the two wire operations, not a synthetic composite.

Not atomic: a concurrent due-date change landing between the GET and the PUT is overwritten with the value this call read. The window is one round-trip.

Instance Method Summary collapse

Instance Method Details

#update(card_id:, title: nil, content: nil, due_on: nil, assignee_ids: nil) ⇒ Hash

Updates a card without disturbing fields the caller did not mention.

due_on is tri-state, which is what makes this safe:

  • nil (omitted) — the current due date is fetched and resent
  • "" — the due date is cleared
  • a date — the due date is set

The extra GET is only paid for in the nil case, the one where the API would otherwise destroy something.

Assignees are never resent on the caller's behalf: BC3 filters incoming IDs through reachable_people, so echoing back an id belonging to someone who has since lost board access would silently unassign them.

Parameters:

  • card_id (Integer)

    card id

  • title (String, nil) (defaults to: nil)

    new title (nil = keep current)

  • content (String, nil) (defaults to: nil)

    new content (nil = keep current, "" clears)

  • due_on (String, nil) (defaults to: nil)

    new due date (nil = keep current, "" clears)

  • assignee_ids (Array, nil) (defaults to: nil)

    new assignees (nil = keep current, [] clears)

Returns:

  • (Hash)

    the updated card



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/basecamp/services/cards_extensions.rb', line 43

def update(card_id:, title: nil, content: nil, due_on: nil, assignee_ids: nil)
  resolved_due_on =
    if due_on.nil?
      get(card_id: card_id)["due_on"]
    elsif due_on.to_s.empty?
      # Clearing is encoded by OMITTING due_on — compact_params strips the
      # nil below, and BC3 nils an omitted due date. Sending an explicit
      # null would violate body compaction (SPEC §18), and sending ""
      # risks a date-format error.
      nil
    else
      due_on
    end

  update_verbatim(
    card_id: card_id,
    title: title,
    content: content,
    due_on: resolved_due_on,
    assignee_ids: assignee_ids
  )
end