Module: Basecamp::Services::TodosExtensions

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

Overview

Merge-safe update and read-modify-write edit for todos, prepended onto the generated TodosService (see the on_load hook in basecamp.rb).

Both compose the public get and replace methods, so hooks observe the two wire operations (+get+ then replace), not a synthetic composite.

Neither is atomic: there is no conditional-update signal on this endpoint, so a concurrent write between the GET and PUT is overwritten — last write wins for the whole representation. The window is one round-trip. Use replace to overwrite deliberately.

Defined Under Namespace

Classes: TodoFields

Instance Method Summary collapse

Instance Method Details

#edit(todo_id:) {|fields| ... } ⇒ Hash

Applies a read-modify-write block to a todo: GETs the current todo, yields its full writable state (TodoFields), and PUTs the whole thing back. Clearing a field means setting it empty (+""+ / []) — an untouched field keeps its current value. If the block raises, the edit aborts and nothing is written.

Not atomic — see the module docs for the GET→PUT race.

Examples:

.todos.edit(todo_id: 123) do |t|
  t.content = "🚨 #{t.content}"
  t.due_on = "" # clearing = setting empty on a full object
end

Parameters:

  • todo_id (Integer)

    todo id

Yield Parameters:

  • fields (TodoFields)

    the todo's writable state, to mutate in place

Returns:

  • (Hash)

    the updated todo

Raises:

  • (ArgumentError)

    if no block is given



77
78
79
80
81
82
83
# File 'lib/basecamp/services/todos_extensions.rb', line 77

def edit(todo_id:)
  raise ArgumentError, "edit requires a block" unless block_given?

  fields = fields_from_todo(get(todo_id: todo_id))
  yield fields
  put_fields(todo_id, fields)
end

#update(todo_id:, content: nil, description: nil, assignee_ids: nil, completion_subscriber_ids: nil, notify: nil, due_on: nil, starts_on: nil) ⇒ Hash

Sets the given fields on a todo and preserves everything else: GETs the current todo, overlays the explicitly-passed keyword arguments, and PUTs the full representation back. An omitted (+nil+) field is untouched, guaranteed; an explicitly-passed empty array clears.

Not atomic — see the module docs for the GET→PUT race. Use #replace to overwrite deliberately, or #edit to clear fields.

Parameters:

  • todo_id (Integer)

    todo id

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

    new content (nil = keep current)

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

    new description (nil = keep current)

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

    complete assignee list ([] clears)

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

    complete subscriber list ([] clears)

  • notify (Boolean, nil) (defaults to: nil)

    notify assignees about this write

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

    due date YYYY-MM-DD (nil = keep current)

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

    start date YYYY-MM-DD (nil = keep current)

Returns:

  • (Hash)

    the updated todo



47
48
49
50
51
52
53
54
55
56
57
# File 'lib/basecamp/services/todos_extensions.rb', line 47

def update(todo_id:, content: nil, description: nil, assignee_ids: nil, completion_subscriber_ids: nil, notify: nil, due_on: nil, starts_on: nil)
  fields = fields_from_todo(get(todo_id: todo_id))
  fields.content = content unless content.nil?
  fields.description = description unless description.nil?
  fields.assignee_ids = assignee_ids unless assignee_ids.nil?
  fields.completion_subscriber_ids = completion_subscriber_ids unless completion_subscriber_ids.nil?
  fields.due_on = due_on unless due_on.nil?
  fields.starts_on = starts_on unless starts_on.nil?
  fields.notify = notify unless notify.nil?
  put_fields(todo_id, fields)
end