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.
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | # File 'lib/parse/model/core/actions.rb', line 384 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.
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 | # File 'lib/parse/model/core/actions.rb', line 656 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.
564 565 566 567 568 569 570 571 572 | # File 'lib/parse/model/core/actions.rb', line 564 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.
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | # File 'lib/parse/model/core/actions.rb', line 445 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.
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 | # File 'lib/parse/model/core/actions.rb', line 539 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.
366 367 368 369 370 371 372 | # File 'lib/parse/model/core/actions.rb', line 366 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.
299 300 301 | # File 'lib/parse/model/core/actions.rb', line 299 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.
335 336 337 338 339 340 | # File 'lib/parse/model/core/actions.rb', line 335 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.
309 310 311 | # File 'lib/parse/model/core/actions.rb', line 309 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.
326 327 328 | # File 'lib/parse/model/core/actions.rb', line 326 def op_destroy!(field) operate_field! field, { __op: :Delete }.freeze end |
#op_increment!(field, amount = 1) ⇒ Object
Atomically increment or decrement a specific field.
358 359 360 361 362 363 | # File 'lib/parse/model/core/actions.rb', line 358 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.
318 319 320 | # File 'lib/parse/model/core/actions.rb', line 318 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.
347 348 349 350 351 352 | # File 'lib/parse/model/core/actions.rb', line 347 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.
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | # File 'lib/parse/model/core/actions.rb', line 278 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.
559 560 561 | # File 'lib/parse/model/core/actions.rb', line 559 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.
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | # File 'lib/parse/model/core/actions.rb', line 582 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
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | # File 'lib/parse/model/core/actions.rb', line 492 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.
530 531 532 | # File 'lib/parse/model/core/actions.rb', line 530 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.
645 646 647 648 649 650 651 652 | # File 'lib/parse/model/core/actions.rb', line 645 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.
438 439 440 441 | # File 'lib/parse/model/core/actions.rb', line 438 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.
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | # File 'lib/parse/model/core/actions.rb', line 418 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.
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 | # File 'lib/parse/model/core/actions.rb', line 605 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 |