Module: Airtable::ORM::Persistence
Constant Summary collapse
- BATCH_SIZE =
10- MAX_FIND_MANY_IDS =
500- RECORD_ID_FORMAT =
Airtable record IDs: rec + alphanumeric characters. Validated before any ID reaches a URL path or formula interpolation (injection guard).
/\Arec[a-zA-Z0-9_-]+\z/
Instance Method Summary collapse
-
#apply_response_fields(data) ⇒ Object
Apply response fields from a create, update, or batch operation.
-
#assign_persistence_state(id:, created_at:, persisted:) ⇒ Object
Assign persistence metadata (id, created_at, persisted flag).
- #client ⇒ Object
-
#create_record ⇒ Object
Create a new record via API.
-
#destroy ⇒ Object
Destroy the record.
-
#destroyed? ⇒ Boolean
Check if this record has been destroyed.
-
#handle_persistence_response(response) ⇒ Object
Handle API response from create/update operations.
-
#initialize(**attributes) ⇒ Object
Initialize a record with symbol attributes Usage: new(email: "test@example.com", first_name: "John").
-
#new_record? ⇒ Boolean
Check if this is a new record (not yet saved).
-
#persisted? ⇒ Boolean
Check if this record has been saved.
-
#previously_new_record? ⇒ Boolean
Check if this record was new before the last save.
-
#reload ⇒ Object
Reload the record from the API.
-
#save(validate: true) ⇒ Object
Save the record (create or update).
-
#save!(validate: true) ⇒ Object
Save the record, raising an error if it fails.
-
#update(attributes) ⇒ Object
Update attributes and save.
-
#update!(attributes) ⇒ Object
Update attributes and save, raising an error if it fails.
-
#update_record ⇒ Object
Update only changed fields via PATCH.
Instance Method Details
#apply_response_fields(data) ⇒ Object
Apply response fields from a create, update, or batch operation. Uses changes_applied (not clear_changes_information) so after_save callbacks can inspect previous_changes / saved_change_to_*? methods.
318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/airtable/orm/persistence.rb', line 318 def apply_response_fields(data) @previously_new_record = new_record? symbol_attrs = self.class.fields_to_symbol_attributes(data["fields"]) symbol_attrs.each { |key, value| write_raw_attribute(key, value) } assign_persistence_state( id: data["id"], created_at: self.class.parse_created_time(data), persisted: true ) changes_applied end |
#assign_persistence_state(id:, created_at:, persisted:) ⇒ Object
Assign persistence metadata (id, created_at, persisted flag)
309 310 311 312 313 |
# File 'lib/airtable/orm/persistence.rb', line 309 def assign_persistence_state(id:, created_at:, persisted:) @id = id @created_at = created_at @persisted = persisted end |
#client ⇒ Object
332 333 334 |
# File 'lib/airtable/orm/persistence.rb', line 332 def client self.class.client end |
#create_record ⇒ Object
Create a new record via API
348 349 350 351 352 353 354 355 |
# File 'lib/airtable/orm/persistence.rb', line 348 def create_record run_callbacks :create do body = { fields: fields_for_create } response = client.connection.post(self.class.api_path, body) handle_persistence_response(response) true end end |
#destroy ⇒ Object
Destroy the record
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/airtable/orm/persistence.rb', line 273 def destroy raise Airtable::ORM::RecordNotDestroyed, "Cannot destroy a new record" if new_record? run_callbacks :destroy do response = client.connection.delete(self.class.api_path(id)) parsed_response = response.body if response.success? @persisted = false @destroyed = true freeze self else Airtable::ORM::Http::Client.raise_api_error(response.status, parsed_response) end end end |
#destroyed? ⇒ Boolean
Check if this record has been destroyed
224 225 226 |
# File 'lib/airtable/orm/persistence.rb', line 224 def destroyed? @destroyed == true end |
#handle_persistence_response(response) ⇒ Object
Handle API response from create/update operations
337 338 339 340 341 342 343 344 345 |
# File 'lib/airtable/orm/persistence.rb', line 337 def handle_persistence_response(response) parsed = response.body if response.success? apply_response_fields(parsed) else Airtable::ORM::Http::Client.raise_api_error(response.status, parsed) end end |
#initialize(**attributes) ⇒ Object
Initialize a record with symbol attributes Usage: new(email: "test@example.com", first_name: "John")
198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/airtable/orm/persistence.rb', line 198 def initialize(**attributes) # Initialize as a new record (not persisted, not destroyed) @id = nil @created_at = nil @persisted = false @destroyed = false @previously_new_record = false # Initialize ActiveModel::Attributes super() # Set attributes using ActiveModel's assign_attributes assign_attributes(attributes) if attributes.present? end |
#new_record? ⇒ Boolean
Check if this is a new record (not yet saved)
214 215 216 |
# File 'lib/airtable/orm/persistence.rb', line 214 def new_record? !@persisted && !@destroyed end |
#persisted? ⇒ Boolean
Check if this record has been saved
219 220 221 |
# File 'lib/airtable/orm/persistence.rb', line 219 def persisted? @persisted == true end |
#previously_new_record? ⇒ Boolean
Check if this record was new before the last save
229 230 231 |
# File 'lib/airtable/orm/persistence.rb', line 229 def previously_new_record? @previously_new_record == true end |
#reload ⇒ Object
Reload the record from the API
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/airtable/orm/persistence.rb', line 292 def reload raise Airtable::ORM::RecordNotPersisted, "Cannot reload a new record" if new_record? fresh_record = self.class.find(id) # Copy attributes from fresh record using raw attribute access self.class.attribute_types.each_key do |name| write_raw_attribute(name.to_sym, fresh_record.read_raw_attribute(name.to_sym)) end @created_at = fresh_record.created_at clear_changes_information self end |
#save(validate: true) ⇒ Object
Save the record (create or update)
234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/airtable/orm/persistence.rb', line 234 def save(validate: true) return false if validate && invalid? result = run_callbacks(:save) do new_record? ? create_record : update_record end result != false rescue Airtable::ORM::ApiError false end |
#save!(validate: true) ⇒ Object
Save the record, raising an error if it fails. Unlike save, lets ApiError propagate with full error details.
248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/airtable/orm/persistence.rb', line 248 def save!(validate: true) raise Airtable::ORM::RecordInvalid, self if validate && invalid? result = run_callbacks(:save) do new_record? ? create_record : update_record end raise Airtable::ORM::RecordNotSaved, "Failed to save the record" if result == false true end |
#update(attributes) ⇒ Object
Update attributes and save
261 262 263 264 |
# File 'lib/airtable/orm/persistence.rb', line 261 def update(attributes) assign_attributes(attributes) save end |
#update!(attributes) ⇒ Object
Update attributes and save, raising an error if it fails
267 268 269 270 |
# File 'lib/airtable/orm/persistence.rb', line 267 def update!(attributes) assign_attributes(attributes) save! end |
#update_record ⇒ Object
Update only changed fields via PATCH. Fields changed TO nil are sent (to clear them in Airtable); unchanged nil fields are not sent.
359 360 361 362 363 364 365 366 367 368 369 370 371 |
# File 'lib/airtable/orm/persistence.rb', line 359 def update_record unless changed? clear_changes_information return true end run_callbacks :update do body = { fields: fields_for_update } response = client.connection.patch(self.class.api_path(id), body) handle_persistence_response(response) true end end |