Method: Dynamoid::Persistence#update!

Defined in:
lib/dynamoid/persistence.rb

#update!(conditions = {}) ⇒ Dynamoid::Document

Update a model.

Doesn’t run validation. Runs only update callbacks. Reloads all attribute values.

Accepts mandatory block in order to specify operations which will modify attributes. Supports following operations: add, delete and set.

Operation add just adds a value for numeric attributes and join collections if attribute is a set.

user.update! do |t|
  t.add(age: 1, followers_count: 5)
  t.add(hobbies: ['skying', 'climbing'])
end

Operation delete is applied to collection attribute types and substructs one collection from another.

user.update! do |t|
  t.delete(hobbies: ['skying'])
end

Operation set just changes an attribute value:

user.update! do |t|
  t.set(age: 21)
end

All the operations work like ADD, DELETE and PUT actions supported by AttributeUpdates parameter of UpdateItem operation.

It’s atomic operations. So adding or deleting elements in a collection or incrementing or decrementing a numeric field is atomic and does not interfere with other write requests.

Can update a model conditionaly:

user.update!(if: { age: 20 }) do |t|
  t.add(age: 1)
end

To check if some attribute (or attributes) isn’t stored in a DynamoDB item (e.g. it wasn’t set explicitly) there is another condition - unless_exists:

user = User.create(name: 'Tylor')
user.update!(unless_exists: [:age]) do |t|
  t.set(age: 18)
end

If a document doesn’t meet conditions it raises Dynamoid::Errors::StaleObjectError exception.

It will increment the lock_version attribute if a table has the column, but will not check it. Thus, a concurrent save call will never cause an update! to fail, but an update! may cause a concurrent save to fail.

Parameters:

  • conditions (Hash) (defaults to: {})

    Conditions on model attributes to make a conditional update (optional)

Returns:



905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
# File 'lib/dynamoid/persistence.rb', line 905

def update!(conditions = {})
  run_callbacks(:update) do
    options = {}
    if range_key
      value = read_attribute(range_key)
      attribute_options = self.class.attributes[range_key]
      options[:range_key] = Dumping.dump_field(value, attribute_options)
    end

    begin
      table_name = self.class.table_name
      partition_key_dumped = Dumping.dump_field(hash_key, self.class.attributes[self.class.hash_key])
      conditions = conditions.dup
      conditions[:if] ||= {}
      conditions[:if][self.class.hash_key] = partition_key_dumped
      if self.class.range_key
        sort_key_dumped = Dumping.dump_field(range_value, self.class.attributes[self.class.range_key])
        conditions[:if][self.class.range_key] = sort_key_dumped
      end

      update_item_options = options.merge(conditions: conditions)

      new_attrs = Dynamoid.adapter.update_item(table_name, partition_key_dumped, update_item_options) do |t|
        item_updater = ItemUpdaterWithDumping.new(self.class, t)

        item_updater.add(lock_version: 1) if self.class.attributes[:lock_version]

        if self.class.timestamps_enabled?
          item_updater.set(updated_at: DateTime.now.in_time_zone(Time.zone))
        end

        yield t
      end
      load(Undumping.undump_attributes(new_attrs, self.class.attributes))
    rescue Dynamoid::Errors::ConditionalCheckFailedException
      # exception may be raised either because of failed user provided conditions
      # or because of conditions on partition and sort keys. We cannot
      # distinguish these two cases.
      raise Dynamoid::Errors::StaleObjectError.new(self, 'update')
    end
  end

  self
end