Module: Parse::Core::Actions
- Included in:
- Object
- Defined in:
- lib/parse/model/core/actions.rb
Overview
Defines some of the save, update and destroy operations for Parse objects.
Defined Under Namespace
Modules: ClassMethods
Instance Method Summary collapse
-
#change_requests(force = false) ⇒ Array<Parse::Request>
Creates an array of all possible operations that need to be performed on this object.
-
#changes_applied! ⇒ Object
Clears changes information on all collections (array and relations) and all local attributes.
-
#changes_payload ⇒ Hash
(also: #update_payload)
A hash of the list of changes made to this instance.
-
#create ⇒ Boolean
Save the object as a new record, running all callbacks.
-
#destroy(session: nil) ⇒ Boolean
Delete this record from the Parse collection.
-
#destroy_request ⇒ Parse::Request
A destroy_request for the current object.
-
#op_add!(field, objects) ⇒ Boolean
Perform an atomic add operation to the array field.
-
#op_add_relation!(field, objects = []) ⇒ Boolean
Perform an atomic add operation on this relational field.
-
#op_add_unique!(field, objects) ⇒ Boolean
Perform an atomic add unique operation to the array field.
-
#op_destroy!(field) ⇒ Boolean
Perform an atomic delete operation on this field.
-
#op_increment!(field, amount = 1) ⇒ Object
Atomically increment or decrement a specific field.
-
#op_remove!(field, objects) ⇒ Boolean
Perform an atomic remove operation to the array field.
-
#op_remove_relation!(field, objects = []) ⇒ Boolean
Perform an atomic remove operation on this relational field.
-
#operate_field!(field, op_hash) ⇒ Boolean
Perform an atomic operation on this field.
-
#prepare_save! ⇒ Object
Runs all the registered ‘before_save` related callbacks.
-
#relation_change_operations ⇒ Array
Generates an array with two entries for addition and removal operations.
-
#save(session: nil, autoraise: false) ⇒ Boolean
saves the object.
-
#save!(session: nil) ⇒ Boolean
Save this object and raise an exception if it fails.
-
#set_attributes!(hash, dirty_track = false) ⇒ Hash
Performs mass assignment using a hash with the ability to modify dirty tracking.
-
#update ⇒ Boolean
Save all the changes related to this object.
-
#update!(raw: false) ⇒ Boolean
This methods sends an update request for this object with the any change information based on its local attributes.
-
#update_relations ⇒ Boolean
Saves and updates all the relational changes for made to this object.
-
#uri_path ⇒ String
The API uri path for this class.
Instance Method Details
#change_requests(force = false) ⇒ Array<Parse::Request>
Creates an array of all possible operations that need to be performed on this object. This includes all property and relational operation changes.
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
# File 'lib/parse/model/core/actions.rb', line 395 def change_requests(force = false) requests = [] # get the URI path for this object. uri = self.uri_path # generate the request to update the object (PUT) if attribute_changes? || force # if it's new, then we should call :post for creating the object. method = new? ? :post : :put r = Request.new( method, uri, body: attribute_updates) r.tag = object_id requests << r end # if the object is not new, then we can also add all the relational changes # we need to perform. if @id.present? && relation_changes? relation_change_operations.each do |ops| next if ops.empty? r = Request.new( :put, uri, body: ops) r.tag = object_id requests << r end end requests end |
#changes_applied! ⇒ Object
Clears changes information on all collections (array and relations) and all local attributes.
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
# File 'lib/parse/model/core/actions.rb', line 668 def changes_applied! # find all fields that are of type :array fields(:array) do |key,v| proxy = send(key) # clear changes proxy.changes_applied! if proxy.respond_to?(:changes_applied!) end # for all relational fields, relations.each do |key,v| proxy = send(key) # clear changes if they support the method. proxy.changes_applied! if proxy.respond_to?(:changes_applied!) end changes_applied end |
#changes_payload ⇒ Hash Also known as: update_payload
Returns a hash of the list of changes made to this instance.
577 578 579 580 581 582 583 584 585 |
# File 'lib/parse/model/core/actions.rb', line 577 def changes_payload h = attribute_updates if relation_changes? r = relation_change_operations.select { |s| s.present? }.first h.merge!(r) if r.present? end #h.merge!(className: parse_class) unless h.empty? h.as_json end |
#create ⇒ Boolean
Save the object as a new record, running all callbacks.
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
# File 'lib/parse/model/core/actions.rb', line 456 def create run_callbacks :create do res = client.create_object(parse_class, attribute_updates, session_token: _session_token) unless res.error? result = res.result @id = result[Parse::Model::OBJECT_ID] || @id @created_at = result["createdAt"] || @created_at #if the object is created, updatedAt == createdAt @updated_at = result["updatedAt"] || result["createdAt"] || @updated_at # Because beforeSave hooks can change the fields we are saving, any items that were # changed, are returned to us and we should apply those locally to be in sync. set_attributes!(result) end puts "Error creating #{self.parse_class}: #{res.error}" if res.error? res.success? end end |
#destroy(session: nil) ⇒ Boolean
Delete this record from the Parse collection. Only valid if this object has an ‘id`. This will run all the `destroy` callbacks.
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
# File 'lib/parse/model/core/actions.rb', line 552 def destroy(session: nil) @_session_token = _validate_session_token! session, :destroy return false if new? success = false run_callbacks :destroy do res = client.delete_object parse_class, id, session_token: _session_token success = res.success? if success @id = nil changes_applied! elsif self.class.raise_on_save_failure raise Parse::RecordNotSaved.new(self), "Failed to create or save attributes. #{self.parse_class} was not saved." end # Your create action methods here end @_session_token = nil success end |
#destroy_request ⇒ Parse::Request
Returns a destroy_request for the current object.
377 378 379 380 381 382 383 |
# File 'lib/parse/model/core/actions.rb', line 377 def destroy_request return nil unless @id.present? uri = self.uri_path r = Request.new( :delete, uri ) r.tag = object_id r end |
#op_add!(field, objects) ⇒ Boolean
Perform an atomic add operation to the array field.
310 311 312 |
# File 'lib/parse/model/core/actions.rb', line 310 def op_add!(field,objects) operate_field! field, { __op: :Add, objects: objects } end |
#op_add_relation!(field, objects = []) ⇒ Boolean
Perform an atomic add operation on this relational field.
346 347 348 349 350 351 |
# File 'lib/parse/model/core/actions.rb', line 346 def op_add_relation!(field, objects = []) objects = [objects] unless objects.is_a?(Array) return false if objects.empty? relation_action = Parse::RelationAction.new(field, polarity: true, objects: objects) operate_field! field, relation_action end |
#op_add_unique!(field, objects) ⇒ Boolean
Perform an atomic add unique operation to the array field. The objects will only be added if they don’t already exists in the array for that particular field.
320 321 322 |
# File 'lib/parse/model/core/actions.rb', line 320 def op_add_unique!(field,objects) operate_field! field, { __op: :AddUnique, objects: objects } end |
#op_destroy!(field) ⇒ Boolean
Perform an atomic delete operation on this field.
337 338 339 |
# File 'lib/parse/model/core/actions.rb', line 337 def op_destroy!(field) operate_field! field, { __op: :Delete }.freeze end |
#op_increment!(field, amount = 1) ⇒ Object
Atomically increment or decrement a specific field.
369 370 371 372 373 374 |
# File 'lib/parse/model/core/actions.rb', line 369 def op_increment!(field, amount = 1) unless amount.is_a?(Numeric) raise ArgumentError, "Amount should be numeric" end operate_field! field, { __op: :Increment, amount: amount.to_i }.freeze end |
#op_remove!(field, objects) ⇒ Boolean
Perform an atomic remove operation to the array field.
329 330 331 |
# File 'lib/parse/model/core/actions.rb', line 329 def op_remove!(field, objects) operate_field! field, { __op: :Remove, objects: objects } end |
#op_remove_relation!(field, objects = []) ⇒ Boolean
Perform an atomic remove operation on this relational field.
358 359 360 361 362 363 |
# File 'lib/parse/model/core/actions.rb', line 358 def op_remove_relation!(field, objects = []) objects = [objects] unless objects.is_a?(Array) return false if objects.empty? relation_action = Parse::RelationAction.new(field, polarity: false, objects: objects) operate_field! field, relation_action end |
#operate_field!(field, op_hash) ⇒ Boolean
Perform an atomic operation on this field. This operation is done on the Parse server which guarantees the atomicity of the operation. This is the low-level API on performing atomic operations on properties for classes. These methods do not update the current instance with any changes the server may have made to satisfy this operation.
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/parse/model/core/actions.rb', line 289 def operate_field!(field, op_hash) field = field.to_sym field = self.field_map[field] || field if op_hash.is_a?(Parse::RelationAction) op_hash = op_hash.as_json else op_hash = { field => op_hash }.as_json end response = client.update_object(parse_class, id, op_hash, session_token: _session_token ) if response.error? puts "[#{parse_class}:#{field} Operation] #{response.error}" end response.success? end |
#prepare_save! ⇒ Object
Runs all the registered ‘before_save` related callbacks.
572 573 574 |
# File 'lib/parse/model/core/actions.rb', line 572 def prepare_save! run_callbacks(:save) { false } end |
#relation_change_operations ⇒ Array
Generates an array with two entries for addition and removal operations. The first entry of the array will contain a hash of all the change operations regarding adding new relational objects. The second entry in the array is a hash of all the change operations regarding removing relation objects from this field.
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
# File 'lib/parse/model/core/actions.rb', line 594 def relation_change_operations return [{},{}] unless relation_changes? additions = [] removals = [] # go through all the additions of a collection and generate an action to add. relation_updates.each do |field,collection| if collection.additions.count > 0 additions.push Parse::RelationAction.new(field, objects: collection.additions, polarity: true) end # go through all the additions of a collection and generate an action to remove. if collection.removals.count > 0 removals.push Parse::RelationAction.new(field, objects: collection.removals, polarity: false) end end # merge all additions and removals into one large hash additions = additions.reduce({}) { |m,v| m.merge! v.as_json } removals = removals.reduce({}) { |m,v| m.merge! v.as_json } [additions, removals] end |
#save(session: nil, autoraise: false) ⇒ Boolean
saves the object. If the object has not changed, it is a noop. If it is new, we will create the object. If the object has an id, we will update the record.
You may pass a session token to the ‘session` argument to perform this actions with the privileges of a certain user.
You can define before and after :save callbacks autoraise: set to true will automatically raise an exception if the save fails
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
# File 'lib/parse/model/core/actions.rb', line 503 def save(session: nil, autoraise: false) @_session_token = _validate_session_token! session, :save return true unless changed? success = false run_callbacks :save do #first process the create/update action if any #then perform any relation changes that need to be performed success = new? ? create : update # if the save was successful and we have relational changes # let's update send those next. if success if relation_changes? # get the list of changed keys changed_attribute_keys = changed - relations.keys.map(&:to_s) clear_attribute_changes( changed_attribute_keys ) success = update_relations if success changes_applied! elsif self.class.raise_on_save_failure || autoraise.present? raise Parse::RecordNotSaved.new(self), "Failed updating relations. #{self.parse_class} partially saved." end else changes_applied! end elsif self.class.raise_on_save_failure || autoraise.present? raise Parse::RecordNotSaved.new(self), "Failed to create or save attributes. #{self.parse_class} was not saved." end end #callbacks @_session_token = nil success end |
#save!(session: nil) ⇒ Boolean
Save this object and raise an exception if it fails.
542 543 544 |
# File 'lib/parse/model/core/actions.rb', line 542 def save!(session: nil) save(autoraise: true, session: session) end |
#set_attributes!(hash, dirty_track = false) ⇒ Hash
Performs mass assignment using a hash with the ability to modify dirty tracking. This is an internal method used to set properties on the object while controlling whether they are dirty tracked. Each defined property has a method defined with the suffix ‘_set_attribute!` that can will be called if it is contained in the hash.
657 658 659 660 661 662 663 664 |
# File 'lib/parse/model/core/actions.rb', line 657 def set_attributes!(hash, dirty_track = false) return unless hash.is_a?(Hash) hash.each do |k,v| next if k == Parse::Model::OBJECT_ID || k == Parse::Model::ID method = "#{k}_set_attribute!" send(method, v, dirty_track) if respond_to?(method) end end |
#update ⇒ Boolean
Save all the changes related to this object.
449 450 451 452 |
# File 'lib/parse/model/core/actions.rb', line 449 def update return true unless attribute_changes? update! end |
#update!(raw: false) ⇒ Boolean
This methods sends an update request for this object with the any change information based on its local attributes. The bang implies that it will send the request even though it is possible no changes were performed. This is useful in kicking-off an beforeSave / afterSave hooks Save the object regardless of whether there are changes. This would call any beforeSave and afterSave cloud code hooks you have registered for this class.
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
# File 'lib/parse/model/core/actions.rb', line 429 def update!(raw: false) if valid? == false errors..each do |msg| warn "[#{parse_class}] warning: #{msg}" end end response = client.update_object(parse_class, id, attribute_updates, session_token: _session_token) if response.success? result = response.result # Because beforeSave hooks can change the fields we are saving, any items that were # changed, are returned to us and we should apply those locally to be in sync. set_attributes!(result) end puts "Error updating #{self.parse_class}: #{response.error}" if response.error? return response if raw response.success? end |
#update_relations ⇒ Boolean
Saves and updates all the relational changes for made to this object.
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 |
# File 'lib/parse/model/core/actions.rb', line 617 def update_relations # relational saves require an id return false unless @id.present? # verify we have relational changes before we do work. return true unless relation_changes? raise "Unable to update relations for a new object." if new? # get all the relational changes (both additions and removals) additions, removals = relation_change_operations responses = [] # Send parallel Parse requests for each of the items to update. # since we will have multiple responses, we will track it in array [removals, additions].threaded_each do |ops| next if ops.empty? #if no operations to be performed, then we are done responses << client.update_object(parse_class, @id, ops, session_token: _session_token) end # check if any of them ended up in error has_error = responses.any? { |response| response.error? } # if everything was ok, find the last response to be returned and update #their fields in case beforeSave made any changes. unless has_error || responses.empty? result = responses.last.result #last result to come back set_attributes!(result) end #unless has_error == false end |