monday_ruby 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -1
  3. data/.rspec +0 -1
  4. data/.rubocop.yml +19 -0
  5. data/.simplecov +1 -0
  6. data/CHANGELOG.md +49 -0
  7. data/CONTRIBUTING.md +165 -0
  8. data/README.md +167 -88
  9. data/docs/.vitepress/config.mjs +255 -0
  10. data/docs/.vitepress/theme/index.js +4 -0
  11. data/docs/.vitepress/theme/style.css +43 -0
  12. data/docs/README.md +80 -0
  13. data/docs/explanation/architecture.md +507 -0
  14. data/docs/explanation/best-practices/errors.md +478 -0
  15. data/docs/explanation/best-practices/performance.md +1084 -0
  16. data/docs/explanation/best-practices/rate-limiting.md +630 -0
  17. data/docs/explanation/best-practices/testing.md +820 -0
  18. data/docs/explanation/column-values.md +857 -0
  19. data/docs/explanation/design.md +795 -0
  20. data/docs/explanation/graphql.md +356 -0
  21. data/docs/explanation/migration/v1.md +808 -0
  22. data/docs/explanation/pagination.md +447 -0
  23. data/docs/guides/advanced/batch.md +1274 -0
  24. data/docs/guides/advanced/complex-queries.md +1114 -0
  25. data/docs/guides/advanced/errors.md +818 -0
  26. data/docs/guides/advanced/pagination.md +934 -0
  27. data/docs/guides/advanced/rate-limiting.md +981 -0
  28. data/docs/guides/authentication.md +286 -0
  29. data/docs/guides/boards/create.md +386 -0
  30. data/docs/guides/boards/delete.md +405 -0
  31. data/docs/guides/boards/duplicate.md +511 -0
  32. data/docs/guides/boards/query.md +530 -0
  33. data/docs/guides/boards/update.md +453 -0
  34. data/docs/guides/columns/create.md +452 -0
  35. data/docs/guides/columns/metadata.md +492 -0
  36. data/docs/guides/columns/query.md +455 -0
  37. data/docs/guides/columns/update-multiple.md +459 -0
  38. data/docs/guides/columns/update-values.md +509 -0
  39. data/docs/guides/files/add-to-column.md +40 -0
  40. data/docs/guides/files/add-to-update.md +37 -0
  41. data/docs/guides/files/clear-column.md +33 -0
  42. data/docs/guides/first-request.md +285 -0
  43. data/docs/guides/folders/manage.md +750 -0
  44. data/docs/guides/groups/items.md +626 -0
  45. data/docs/guides/groups/manage.md +501 -0
  46. data/docs/guides/installation.md +169 -0
  47. data/docs/guides/items/create.md +493 -0
  48. data/docs/guides/items/delete.md +514 -0
  49. data/docs/guides/items/query.md +605 -0
  50. data/docs/guides/items/subitems.md +483 -0
  51. data/docs/guides/items/update.md +699 -0
  52. data/docs/guides/updates/manage.md +619 -0
  53. data/docs/guides/use-cases/dashboard.md +1421 -0
  54. data/docs/guides/use-cases/import.md +1962 -0
  55. data/docs/guides/use-cases/task-management.md +1381 -0
  56. data/docs/guides/workspaces/manage.md +502 -0
  57. data/docs/index.md +69 -0
  58. data/docs/package-lock.json +2468 -0
  59. data/docs/package.json +13 -0
  60. data/docs/reference/client.md +540 -0
  61. data/docs/reference/configuration.md +586 -0
  62. data/docs/reference/errors.md +693 -0
  63. data/docs/reference/resources/account.md +208 -0
  64. data/docs/reference/resources/activity-log.md +369 -0
  65. data/docs/reference/resources/board-view.md +359 -0
  66. data/docs/reference/resources/board.md +393 -0
  67. data/docs/reference/resources/column.md +543 -0
  68. data/docs/reference/resources/file.md +236 -0
  69. data/docs/reference/resources/folder.md +386 -0
  70. data/docs/reference/resources/group.md +507 -0
  71. data/docs/reference/resources/item.md +348 -0
  72. data/docs/reference/resources/subitem.md +267 -0
  73. data/docs/reference/resources/update.md +259 -0
  74. data/docs/reference/resources/workspace.md +213 -0
  75. data/docs/reference/response.md +560 -0
  76. data/docs/tutorial/first-integration.md +713 -0
  77. data/lib/monday/client.rb +41 -2
  78. data/lib/monday/configuration.rb +13 -0
  79. data/lib/monday/deprecation.rb +23 -0
  80. data/lib/monday/error.rb +5 -2
  81. data/lib/monday/request.rb +19 -1
  82. data/lib/monday/resources/base.rb +4 -0
  83. data/lib/monday/resources/board.rb +52 -0
  84. data/lib/monday/resources/column.rb +6 -0
  85. data/lib/monday/resources/file.rb +56 -0
  86. data/lib/monday/resources/folder.rb +55 -0
  87. data/lib/monday/resources/group.rb +66 -0
  88. data/lib/monday/resources/item.rb +62 -0
  89. data/lib/monday/util.rb +33 -1
  90. data/lib/monday/version.rb +1 -1
  91. data/lib/monday_ruby.rb +1 -0
  92. metadata +92 -11
  93. data/monday_ruby.gemspec +0 -39
@@ -0,0 +1,857 @@
1
+ # Column Values in monday.com
2
+
3
+ This document explains the concept of column values, their types, formats, and why they work the way they do in the monday.com API.
4
+
5
+ ## What are Column Values?
6
+
7
+ In monday.com, column values are the data stored in the cells of a board. Each item (row) has values for each column (field) defined on its board. Unlike traditional databases where column types are strictly defined, monday.com supports a rich variety of column types, each with its own value structure and behavior.
8
+
9
+ ### The monday.com Data Model
10
+
11
+ ```
12
+ Board
13
+ ├── Group 1
14
+ │ ├── Item A
15
+ │ │ ├── Status Column: "Done"
16
+ │ │ ├── Date Column: "2024-01-15"
17
+ │ │ └── Person Column: [User 123, User 456]
18
+ │ └── Item B
19
+ └── Group 2
20
+ ```
21
+
22
+ Each cell in this structure contains a column value. The structure and meaning of that value depends on the column type.
23
+
24
+ ### Column Values vs Column Definitions
25
+
26
+ It's important to distinguish between:
27
+
28
+ - **Column definition**: The column itself (its ID, type, title, settings)
29
+ - **Column value**: The data stored in that column for a specific item
30
+
31
+ For example:
32
+ - Column definition: `{id: "status", type: "status", title: "Project Status"}`
33
+ - Column value: `{label: "In Progress", index: 1}`
34
+
35
+ ## Column Types and Their Value Formats
36
+
37
+ monday.com supports numerous column types, each requiring a specific value format.
38
+
39
+ ### Simple Column Types
40
+
41
+ Some column types store simple, straightforward values:
42
+
43
+ **Text**
44
+ ```json
45
+ "This is a text value"
46
+ ```
47
+
48
+ **Number**
49
+ ```json
50
+ "42"
51
+ ```
52
+
53
+ **Checkbox**
54
+ ```json
55
+ {"checked": true}
56
+ ```
57
+
58
+ ### Complex Column Types
59
+
60
+ Many column types have structured, complex values:
61
+
62
+ **Status**
63
+ ```json
64
+ {
65
+ "label": "Done",
66
+ "index": 2
67
+ }
68
+ ```
69
+ Contains both the display label and the index (position in status options).
70
+
71
+ **Date**
72
+ ```json
73
+ {
74
+ "date": "2024-01-15",
75
+ "time": "14:30:00"
76
+ }
77
+ ```
78
+ Supports date-only or date+time values.
79
+
80
+ **Person**
81
+ ```json
82
+ {
83
+ "personsAndTeams": [
84
+ {"id": 12345, "kind": "person"},
85
+ {"id": 67890, "kind": "team"}
86
+ ]
87
+ }
88
+ ```
89
+ Can reference multiple people and/or teams.
90
+
91
+ **Dropdown**
92
+ ```json
93
+ {
94
+ "labels": ["Option 1", "Option 2"]
95
+ }
96
+ ```
97
+ Single or multiple selections depending on column settings.
98
+
99
+ **Link**
100
+ ```json
101
+ {
102
+ "url": "https://example.com",
103
+ "text": "Example Website"
104
+ }
105
+ ```
106
+ URL with optional display text.
107
+
108
+ **Phone**
109
+ ```json
110
+ {
111
+ "phone": "+1-555-123-4567",
112
+ "countryShortName": "US"
113
+ }
114
+ ```
115
+ Phone number with country code.
116
+
117
+ **Email**
118
+ ```json
119
+ {
120
+ "email": "user@example.com",
121
+ "text": "John Doe"
122
+ }
123
+ ```
124
+ Email address with optional display name.
125
+
126
+ **Location**
127
+ ```json
128
+ {
129
+ "lat": "37.7749",
130
+ "lng": "-122.4194",
131
+ "address": "San Francisco, CA"
132
+ }
133
+ ```
134
+ Geographic coordinates and address.
135
+
136
+ **Timeline**
137
+ ```json
138
+ {
139
+ "from": "2024-01-01",
140
+ "to": "2024-12-31"
141
+ }
142
+ ```
143
+ Date range with start and end dates.
144
+
145
+ ## Why Different Column Types Need Different JSON Structures
146
+
147
+ The structural diversity in column value formats reflects the semantic differences between data types.
148
+
149
+ ### Semantic Richness
150
+
151
+ Each column type represents different real-world concepts:
152
+
153
+ - **Status**: Requires both a label (what users see) and an index (for ordering/grouping)
154
+ - **Person**: Must distinguish between individual users and teams, and support multiple assignments
155
+ - **Date**: Needs to handle date-only and date-time scenarios differently
156
+ - **Link**: Separates the destination URL from the display text
157
+
158
+ ### Backend Processing
159
+
160
+ Different column types trigger different backend behaviors:
161
+
162
+ - **Person columns**: Trigger notifications to assigned users
163
+ - **Status columns**: Update board analytics and dashboards
164
+ - **Date columns**: Power timeline views and deadline reminders
165
+ - **Formula columns**: Recalculate when dependent values change
166
+
167
+ The value format provides the data needed for these behaviors.
168
+
169
+ ### Validation Requirements
170
+
171
+ Each column type has unique validation needs:
172
+
173
+ - **Email**: Must validate email format
174
+ - **Phone**: Must validate phone number format and country code
175
+ - **Date**: Must validate date is valid and in correct format
176
+ - **Dropdown**: Must validate selection exists in column settings
177
+
178
+ The structured format enables server-side validation.
179
+
180
+ ### UI Rendering
181
+
182
+ The monday.com interface renders each column type differently:
183
+
184
+ - **Status**: Colored labels with icons
185
+ - **Person**: Avatar images with names
186
+ - **Date**: Calendar picker
187
+ - **Timeline**: Gantt chart visualization
188
+
189
+ The value structure includes all information needed for rendering.
190
+
191
+ ## Simple vs Complex Column Values
192
+
193
+ Column values exist on a spectrum from simple to complex.
194
+
195
+ ### Simple Column Values
196
+
197
+ Types like text, number, and checkbox are "simple":
198
+ - Single primitive value or shallow object
199
+ - Minimal structure
200
+ - Easy to read and write
201
+ - Limited backend processing
202
+
203
+ ```json
204
+ "Simple text"
205
+ ```
206
+
207
+ ### Complex Column Values
208
+
209
+ Types like person, board relation, and mirror are "complex":
210
+ - Deeply nested structures
211
+ - Multiple data points
212
+ - References to other entities
213
+ - Extensive backend processing
214
+
215
+ ```json
216
+ {
217
+ "item_ids": [123, 456, 789],
218
+ "linkedPulseIds": [
219
+ {"linkedPulseId": 123},
220
+ {"linkedPulseId": 456}
221
+ ]
222
+ }
223
+ ```
224
+
225
+ ### The Complexity Spectrum
226
+
227
+ ```
228
+ Simple Complex
229
+ ├─────────┼─────────┼─────────┼─────────┼─────────┤
230
+ Text Number Status Person Board-Relation
231
+ Checkbox Date Dropdown Mirror
232
+ Link Timeline Formula
233
+ ```
234
+
235
+ Complexity affects:
236
+ - **API payload size**: Complex values require more data
237
+ - **Validation logic**: Complex values have more validation rules
238
+ - **Query performance**: Complex values may require joins or lookups
239
+ - **Update latency**: Complex values may trigger cascading updates
240
+
241
+ ## Column IDs vs Column Titles
242
+
243
+ Understanding the difference between column IDs and titles is crucial for working with column values.
244
+
245
+ ### Column Title
246
+
247
+ The title is the human-readable name displayed in the monday.com interface:
248
+ - "Project Status"
249
+ - "Due Date"
250
+ - "Assigned To"
251
+
252
+ Titles are:
253
+ - User-facing and editable
254
+ - Not guaranteed to be unique
255
+ - Can change at any time
256
+ - Localized in some cases
257
+
258
+ ### Column ID
259
+
260
+ The ID is a unique identifier for the column:
261
+ - "status"
262
+ - "date4"
263
+ - "person"
264
+
265
+ IDs are:
266
+ - System-facing and stable
267
+ - Guaranteed unique within a board
268
+ - Generally don't change (though they can)
269
+ - Not localized
270
+
271
+ ### Why IDs are Board-Specific
272
+
273
+ Column IDs are only unique within a board:
274
+ - Board A can have a column with ID "status"
275
+ - Board B can also have a column with ID "status"
276
+ - These are different columns with potentially different settings
277
+
278
+ This means:
279
+ - You cannot assume column ID "status" has the same meaning across boards
280
+ - When working with multiple boards, track board ID + column ID
281
+ - Column settings (like status options) are board-specific
282
+
283
+ ### API Usage
284
+
285
+ The API uses column IDs, not titles:
286
+
287
+ ```ruby
288
+ # Correct: Use column ID
289
+ client.item.change_column_value(
290
+ args: {
291
+ board_id: 123,
292
+ item_id: 456,
293
+ column_id: "status", # Column ID
294
+ value: '{"label": "Done"}'
295
+ }
296
+ )
297
+
298
+ # Incorrect: Cannot use column title
299
+ client.item.change_column_value(
300
+ args: {
301
+ column_id: "Project Status", # Won't work!
302
+ ...
303
+ }
304
+ )
305
+ ```
306
+
307
+ ### Finding Column IDs
308
+
309
+ To find column IDs:
310
+ 1. Query the board's columns
311
+ 2. Match by title to find the corresponding ID
312
+ 3. Use the ID in subsequent operations
313
+
314
+ ```ruby
315
+ # Get column information
316
+ response = client.board.query(
317
+ args: { ids: [123] },
318
+ select: [{ columns: ["id", "title", "type"] }]
319
+ )
320
+
321
+ # Find column ID by title
322
+ columns = response.dig("data", "boards", 0, "columns")
323
+ status_column = columns.find { |col| col["title"] == "Project Status" }
324
+ column_id = status_column["id"] # Use this ID
325
+ ```
326
+
327
+ ## JSON Serialization Requirements
328
+
329
+ Column values are passed as JSON strings in the monday.com API, which has important implications.
330
+
331
+ ### Why JSON Strings?
332
+
333
+ The API requires column values as JSON-encoded strings rather than native objects:
334
+
335
+ ```ruby
336
+ # Correct: JSON string
337
+ value = '{"label": "Done"}'
338
+
339
+ # Incorrect: Ruby hash
340
+ value = {label: "Done"} # Won't work!
341
+ ```
342
+
343
+ **Reasons for this design**:
344
+
345
+ 1. **GraphQL limitations**: GraphQL mutations require static types, but column values vary by column type
346
+ 2. **Flexibility**: JSON strings can represent any column type without defining dozens of input types
347
+ 3. **Backward compatibility**: New column types can be added without API changes
348
+ 4. **Validation**: Server can validate after parsing based on actual column type
349
+
350
+ ### Serialization Process
351
+
352
+ When setting a column value:
353
+
354
+ 1. **Construct**: Build a Ruby hash with the value structure
355
+ ```ruby
356
+ value_hash = {label: "Done", index: 2}
357
+ ```
358
+
359
+ 2. **Serialize**: Convert to JSON string
360
+ ```ruby
361
+ value_json = value_hash.to_json
362
+ # => '{"label":"Done","index":2}'
363
+ ```
364
+
365
+ 3. **Send**: Pass the JSON string to the API
366
+ ```ruby
367
+ client.item.change_column_value(
368
+ args: { column_id: "status", value: value_json }
369
+ )
370
+ ```
371
+
372
+ ### Deserialization Process
373
+
374
+ When reading column values:
375
+
376
+ 1. **Receive**: Get JSON string from API
377
+ ```ruby
378
+ column_value = response.dig("data", "items", 0, "column_values", 0, "value")
379
+ # => '{"label":"Done","index":2}'
380
+ ```
381
+
382
+ 2. **Parse**: Convert from JSON string to Ruby hash
383
+ ```ruby
384
+ value_hash = JSON.parse(column_value)
385
+ # => {"label"=>"Done", "index"=>2}
386
+ ```
387
+
388
+ 3. **Use**: Access the parsed data
389
+ ```ruby
390
+ label = value_hash["label"] # => "Done"
391
+ ```
392
+
393
+ ### Common Serialization Pitfalls
394
+
395
+ **Double encoding**:
396
+ ```ruby
397
+ # Wrong: Double encoding
398
+ value = {label: "Done"}.to_json.to_json
399
+ # => '"{\"label\":\"Done\"}"' # Escaped quotes!
400
+
401
+ # Correct: Single encoding
402
+ value = {label: "Done"}.to_json
403
+ # => '{"label":"Done"}'
404
+ ```
405
+
406
+ **Symbol vs string keys**:
407
+ ```ruby
408
+ # Both work, but consistency matters
409
+ {label: "Done"}.to_json # => '{"label":"Done"}'
410
+ {"label" => "Done"}.to_json # => '{"label":"Done"}'
411
+
412
+ # Parsing returns string keys
413
+ JSON.parse('{"label":"Done"}')
414
+ # => {"label"=>"Done"} # String keys, not symbols
415
+ ```
416
+
417
+ **Escaping**:
418
+ ```ruby
419
+ # Special characters must be properly escaped
420
+ value = {text: 'Quote: "Hello"'}.to_json
421
+ # => '{"text":"Quote: \"Hello\""}'
422
+ ```
423
+
424
+ ## change_value vs change_simple_value vs change_multiple_values
425
+
426
+ monday.com provides multiple methods for updating column values, each optimized for different scenarios.
427
+
428
+ ### change_column_value
429
+
430
+ Updates a single column value on a single item:
431
+
432
+ ```ruby
433
+ client.item.change_column_value(
434
+ args: {
435
+ board_id: 123,
436
+ item_id: 456,
437
+ column_id: "status",
438
+ value: '{"label": "Done"}'
439
+ }
440
+ )
441
+ ```
442
+
443
+ **Characteristics**:
444
+ - Most explicit and clear
445
+ - Requires full value structure
446
+ - Works with any column type
447
+ - Validates against column type
448
+ - Returns updated item
449
+
450
+ **Use when**:
451
+ - Updating complex column values
452
+ - Need full control over value structure
453
+ - Working with a single column
454
+
455
+ ### change_simple_column_value
456
+
457
+ Simplified version for common column types:
458
+
459
+ ```ruby
460
+ client.item.change_simple_column_value(
461
+ args: {
462
+ board_id: 123,
463
+ item_id: 456,
464
+ column_id: "text_column",
465
+ value: "Simple text" # Plain string, not JSON
466
+ }
467
+ )
468
+ ```
469
+
470
+ **Characteristics**:
471
+ - Accepts plain strings for simple types
472
+ - Automatically handles JSON encoding
473
+ - Limited to simple column types (text, number)
474
+ - Less flexible than `change_column_value`
475
+
476
+ **Use when**:
477
+ - Updating text or number columns
478
+ - Value is a simple string or number
479
+ - Want simplified API
480
+
481
+ ### change_multiple_column_values
482
+
483
+ Updates multiple columns on a single item in one request:
484
+
485
+ ```ruby
486
+ client.item.change_multiple_column_values(
487
+ args: {
488
+ board_id: 123,
489
+ item_id: 456,
490
+ column_values: {
491
+ status: {label: "Done"},
492
+ date4: {date: "2024-01-15"},
493
+ person: {personsAndTeams: [{id: 12345, kind: "person"}]}
494
+ }.to_json
495
+ }
496
+ )
497
+ ```
498
+
499
+ **Characteristics**:
500
+ - Updates multiple columns atomically
501
+ - More efficient than multiple single-column updates
502
+ - Reduces API calls and complexity
503
+ - Single validation and response
504
+
505
+ **Use when**:
506
+ - Updating several columns at once
507
+ - Creating items with initial values
508
+ - Want to minimize API requests
509
+ - Need atomic updates (all or nothing)
510
+
511
+ ### Method Comparison
512
+
513
+ | Method | Columns per Call | Value Format | Complexity | Use Case |
514
+ |--------|-----------------|--------------|------------|----------|
515
+ | `change_column_value` | 1 | JSON string | Medium | Single column, any type |
516
+ | `change_simple_column_value` | 1 | Plain string | Low | Simple types only |
517
+ | `change_multiple_column_values` | Multiple | JSON string | Higher | Batch updates |
518
+
519
+ ### Performance Implications
520
+
521
+ **Multiple single updates**:
522
+ ```ruby
523
+ # 3 API calls
524
+ client.item.change_column_value(args: {column_id: "status", ...})
525
+ client.item.change_column_value(args: {column_id: "date4", ...})
526
+ client.item.change_column_value(args: {column_id: "person", ...})
527
+ ```
528
+
529
+ **Single batch update**:
530
+ ```ruby
531
+ # 1 API call
532
+ client.item.change_multiple_column_values(
533
+ args: {
534
+ column_values: {
535
+ status: {...},
536
+ date4: {...},
537
+ person: {...}
538
+ }.to_json
539
+ }
540
+ )
541
+ ```
542
+
543
+ Batch updates:
544
+ - 3× fewer API calls
545
+ - 3× less authentication overhead
546
+ - Lower total complexity
547
+ - Faster total execution
548
+ - Atomic (all succeed or all fail)
549
+
550
+ ## Column Value Validation
551
+
552
+ Validation of column values happens on the monday.com server, not in the API client.
553
+
554
+ ### Server-Side Validation
555
+
556
+ When you submit a column value, monday.com validates:
557
+
558
+ 1. **Type compatibility**: Value structure matches column type
559
+ 2. **Required fields**: All necessary fields are present
560
+ 3. **Value constraints**: Values are within allowed ranges/options
561
+ 4. **Reference validity**: Referenced entities (users, boards, etc.) exist
562
+ 5. **Permissions**: User has permission to set the value
563
+
564
+ ### Why Server-Side?
565
+
566
+ - **Authoritative**: Board configuration is server-controlled
567
+ - **Dynamic**: Column settings can change
568
+ - **Security**: Client-side validation can be bypassed
569
+ - **Consistency**: Same validation for all API clients
570
+ - **Complex rules**: Some validation requires server data
571
+
572
+ ### Validation Errors
573
+
574
+ Invalid column values return errors:
575
+
576
+ ```ruby
577
+ # Invalid status label
578
+ client.item.change_column_value(
579
+ args: {
580
+ column_id: "status",
581
+ value: '{"label": "Invalid Status"}'
582
+ }
583
+ )
584
+ # Error: "Status label 'Invalid Status' does not exist"
585
+ ```
586
+
587
+ ```ruby
588
+ # Invalid date format
589
+ client.item.change_column_value(
590
+ args: {
591
+ column_id: "date4",
592
+ value: '{"date": "2024-13-45"}' # Invalid date
593
+ }
594
+ )
595
+ # Error: "Invalid date format"
596
+ ```
597
+
598
+ ### Validation Strategy
599
+
600
+ Best practices for handling validation:
601
+
602
+ 1. **Query column settings**: Fetch column configuration to know valid options
603
+ 2. **Validate client-side**: Pre-validate when possible to avoid API calls
604
+ 3. **Handle errors**: Catch and handle validation errors gracefully
605
+ 4. **Test edge cases**: Test with boundary values and edge cases
606
+ 5. **Monitor changes**: Watch for board configuration changes that affect validation
607
+
608
+ ### Example: Status Column Validation
609
+
610
+ ```ruby
611
+ # 1. Get valid status options
612
+ board = client.board.query(
613
+ args: { ids: [123] },
614
+ select: [{ columns: ["id", "settings_str"] }]
615
+ )
616
+
617
+ status_column = board.dig("data", "boards", 0, "columns")
618
+ .find { |c| c["id"] == "status" }
619
+
620
+ settings = JSON.parse(status_column["settings_str"])
621
+ valid_labels = settings["labels"].keys
622
+ # => ["Not Started", "In Progress", "Done"]
623
+
624
+ # 2. Validate before sending
625
+ label = "Done"
626
+ if valid_labels.include?(label)
627
+ client.item.change_column_value(
628
+ args: {
629
+ column_id: "status",
630
+ value: {label: label}.to_json
631
+ }
632
+ )
633
+ else
634
+ # Handle invalid label
635
+ puts "Invalid status: #{label}"
636
+ end
637
+ ```
638
+
639
+ ## Common Column Value Patterns
640
+
641
+ Certain patterns appear frequently when working with column values.
642
+
643
+ ### Clearing a Column Value
644
+
645
+ To clear a column value, set it to an empty object or null:
646
+
647
+ ```ruby
648
+ # Clear status column
649
+ client.item.change_column_value(
650
+ args: {
651
+ column_id: "status",
652
+ value: '{}'
653
+ }
654
+ )
655
+
656
+ # Clear text column
657
+ client.item.change_simple_column_value(
658
+ args: {
659
+ column_id: "text_column",
660
+ value: ""
661
+ }
662
+ )
663
+ ```
664
+
665
+ ### Copying Column Values Between Items
666
+
667
+ ```ruby
668
+ # Get source item's column value
669
+ source = client.item.query(
670
+ args: { ids: [123] },
671
+ select: [{ column_values: ["id", "value"] }]
672
+ )
673
+
674
+ status_value = source.dig("data", "items", 0, "column_values")
675
+ .find { |cv| cv["id"] == "status" }["value"]
676
+
677
+ # Set on destination item
678
+ client.item.change_column_value(
679
+ args: {
680
+ item_id: 456,
681
+ column_id: "status",
682
+ value: status_value # Already JSON string
683
+ }
684
+ )
685
+ ```
686
+
687
+ ### Conditional Updates
688
+
689
+ ```ruby
690
+ # Update only if current value meets condition
691
+ item = client.item.query(
692
+ args: { ids: [123] },
693
+ select: [{ column_values: ["id", "value"] }]
694
+ )
695
+
696
+ status = JSON.parse(
697
+ item.dig("data", "items", 0, "column_values")
698
+ .find { |cv| cv["id"] == "status" }["value"]
699
+ )
700
+
701
+ if status["label"] == "In Progress"
702
+ # Move to Done
703
+ client.item.change_column_value(
704
+ args: {
705
+ column_id: "status",
706
+ value: '{"label": "Done"}'
707
+ }
708
+ )
709
+ end
710
+ ```
711
+
712
+ ### Bulk Updates Across Items
713
+
714
+ ```ruby
715
+ # Update same column on multiple items
716
+ item_ids = [123, 456, 789]
717
+ value = '{"label": "Done"}'
718
+
719
+ item_ids.each do |item_id|
720
+ client.item.change_column_value(
721
+ args: {
722
+ item_id: item_id,
723
+ column_id: "status",
724
+ value: value
725
+ }
726
+ )
727
+ end
728
+ ```
729
+
730
+ ### Setting Values on Item Creation
731
+
732
+ ```ruby
733
+ # Create item with initial column values
734
+ client.item.create(
735
+ args: {
736
+ board_id: 123,
737
+ item_name: "New Task",
738
+ column_values: {
739
+ status: {label: "Not Started"},
740
+ date4: {date: "2024-12-31"},
741
+ person: {
742
+ personsAndTeams: [
743
+ {id: 12345, kind: "person"}
744
+ ]
745
+ }
746
+ }.to_json
747
+ }
748
+ )
749
+ ```
750
+
751
+ ## Why Column Values are Strings/JSON
752
+
753
+ The decision to represent column values as JSON strings rather than native types has deep architectural reasons.
754
+
755
+ ### GraphQL Type System Constraints
756
+
757
+ GraphQL requires mutations to have statically-typed inputs:
758
+
759
+ ```graphql
760
+ # GraphQL requires knowing exact type at schema definition time
761
+ mutation {
762
+ change_column_value(
763
+ column_id: "status",
764
+ value: StatusInput # Must be a defined input type
765
+ )
766
+ }
767
+ ```
768
+
769
+ With 30+ column types, each with different structures:
770
+ - Defining 30+ input types would be complex
771
+ - Adding new column types would break API compatibility
772
+ - Clients would need to know all types
773
+
774
+ ### JSON as Universal Type
775
+
776
+ Using JSON strings provides a universal interface:
777
+
778
+ ```graphql
779
+ mutation {
780
+ change_column_value(
781
+ column_id: String!,
782
+ value: JSON! # Universal type
783
+ )
784
+ }
785
+ ```
786
+
787
+ Benefits:
788
+ - Single input type for all column values
789
+ - New column types don't require schema changes
790
+ - Backward compatible
791
+ - Forward compatible
792
+
793
+ ### Runtime Type Resolution
794
+
795
+ With JSON strings, monday.com can:
796
+
797
+ 1. **Receive** the value as a string
798
+ 2. **Parse** the JSON
799
+ 3. **Look up** the column type from the database
800
+ 4. **Validate** based on actual column type
801
+ 5. **Process** type-specific logic
802
+
803
+ This allows dynamic, runtime type handling instead of static, compile-time types.
804
+
805
+ ### Trade-off: Type Safety vs Flexibility
806
+
807
+ **Type safety (if native objects were used)**:
808
+ - Compile-time validation
809
+ - Better IDE autocomplete
810
+ - Catch errors earlier
811
+ - More complex API
812
+
813
+ **Flexibility (current JSON string approach)**:
814
+ - Runtime validation
815
+ - Limited IDE support
816
+ - Errors caught later
817
+ - Simpler API
818
+
819
+ monday.com chose flexibility to support its rapidly evolving column type system.
820
+
821
+ ### Client Library Implications
822
+
823
+ The monday_ruby gem could provide typed wrappers:
824
+
825
+ ```ruby
826
+ # Hypothetical typed wrapper (not currently implemented)
827
+ StatusValue.new(label: "Done", index: 2).to_json
828
+ # => '{"label":"Done","index":2}'
829
+ ```
830
+
831
+ This would provide:
832
+ - Type safety in Ruby
833
+ - Validation before API call
834
+ - Better developer experience
835
+ - Documentation through code
836
+
837
+ But would require:
838
+ - Maintaining type definitions for all column types
839
+ - Updates when monday.com adds column types
840
+ - Additional abstraction layer
841
+
842
+ Currently, monday_ruby passes JSON strings directly, keeping the API thin and flexible.
843
+
844
+ ## Conclusion
845
+
846
+ Column values are the core data model in monday.com, representing diverse types of information with varying structural complexity. Understanding column values requires grasping several key concepts:
847
+
848
+ - **Type diversity**: Different column types have different value structures reflecting their semantic meaning
849
+ - **JSON serialization**: Values are passed as JSON strings due to GraphQL constraints and flexibility requirements
850
+ - **Column identification**: Column IDs, not titles, are used for API operations and are board-specific
851
+ - **Multiple update methods**: Different methods (`change_column_value`, `change_simple_column_value`, `change_multiple_column_values`) optimize for different scenarios
852
+ - **Server-side validation**: monday.com validates column values based on board configuration and column settings
853
+ - **Common patterns**: Clearing values, copying between items, and bulk updates follow established patterns
854
+
855
+ The JSON string approach, while requiring extra serialization steps, provides the flexibility necessary for monday.com's rich and evolving column type system. The monday_ruby gem preserves this design while providing Ruby-friendly interfaces for building and parsing these values.
856
+
857
+ Understanding these concepts enables you to effectively work with monday.com's data model, choose the right update methods, handle validation properly, and build robust integrations.