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.
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 = {} if range_key value = read_attribute(range_key) = self.class.attributes[range_key] [:range_key] = Dumping.dump_field(value, ) 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 = .merge(conditions: conditions) new_attrs = Dynamoid.adapter.update_item(table_name, partition_key_dumped, ) do |t| item_updater = ItemUpdaterWithDumping.new(self.class, t) item_updater.add(lock_version: 1) if self.class.attributes[:lock_version] if self.class. 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 |