Module: Basecamp::Services::DocumentsExtensions
- Defined in:
- lib/basecamp/services/documents_extensions.rb
Overview
Merge-safe update and read-modify-write edit for documents,
prepended onto the generated DocumentsService (see the on_load hook
in basecamp.rb).
BC3's DocumentsController#update builds a brand-new Document from
only the permitted params and swaps the recordable wholesale, so
PUT /documents/{id} is a full replace: a body that omits
content ERASES it, and one that omits title erases that too — the
document then reads back as "Untitled", because Document#title
falls back when blank. Neither attribute is presence-validated, so
neither omission is a 422; both are a 200 that quietly clears. What BC3
does require is the wrapping document object, so a body naming neither
field is a 400. The sparse PUT — the natural thing to write — is
therefore destructive on the raw endpoint, which stays available as
#replace.
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: DocumentFields
Constant Summary collapse
- ESCAPE_HATCH =
The deliberate-overwrite escape hatch named in every malformed-response hint raised out of this composite.
"replace"
Instance Method Summary collapse
-
#edit(document_id:) {|fields| ... } ⇒ Hash
Applies a read-modify-write block to a document: GETs the current document, yields its full writable state (DocumentFields), and PUTs the whole thing back.
-
#update(document_id:, title: nil, content: nil) ⇒ Hash
Sets the given fields on a document and preserves everything else: GETs the current document, overlays the explicitly-passed keyword arguments, and PUTs the full representation back.
Instance Method Details
#edit(document_id:) {|fields| ... } ⇒ Hash
Applies a read-modify-write block to a document: GETs the current document, yields its full writable state (DocumentFields), 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.
78 79 80 81 82 83 84 |
# File 'lib/basecamp/services/documents_extensions.rb', line 78 def edit(document_id:) raise ArgumentError, "edit requires a block" unless block_given? fields = fields_from_document(get(document_id: document_id)) yield fields put_fields(document_id, fields) end |
#update(document_id:, title: nil, content: nil) ⇒ Hash
Sets the given fields on a document and preserves everything else: GETs the current document, overlays the explicitly-passed keyword arguments, and PUTs the full representation back. An omitted (+nil+) field is untouched, guaranteed; an explicitly-passed "" clears.
Not atomic — see the module docs for the GET→PUT race. Use #replace to overwrite deliberately.
53 54 55 56 57 58 |
# File 'lib/basecamp/services/documents_extensions.rb', line 53 def update(document_id:, title: nil, content: nil) fields = fields_from_document(get(document_id: document_id)) fields.title = title unless title.nil? fields.content = content unless content.nil? put_fields(document_id, fields) end |