Skip to content

ChangeSets and Dirty Tracking

Trey Pendragon edited this page May 15, 2020 · 11 revisions

ChangeSets are a way to group together properties that should be applied to an underlying resource. They are often used for powering HTML forms, tracking when properties have changed (aka "dirty tracking"), validating input, and storing virtual attributes for special synchronization with a resource.

To use a ChangeSet, validate the properties with the ChangeSet, sync the ChangeSet to the model, and then save the changes through a ChangeSetPersister. Please note that models, by default, can be persisted with invalid data using ChangeSetPersisters, so it is up to an application to validate and not save invalid data. Using strictly typing on the property definitions themselves can also help avoid invalid data being saved.

For more general info on change tracking, see Reform's dirty tracking documentation.

Examples

Resource & MyChangeSet Declaration

    class Resource < Valkyrie::Resource
      attribute: page_number, Valkyrie::Types::Set
    end
    class MyChangeSet < Valkyrie::ChangeSet
      property :page_number
      validates :page_number, presence: true
    end

Entirely changing a property

resource = Resource.new
change_set = MyChangeSet.new(resource)
change_set.validate(page_number: 12)

# Some examples of ways to see that this has changed:
# change_set.changed? # => true
# change_set.changed # => {"page_number" => true}
# change_set.changed["page_number"] # => true

# Sets the value on the model
change_set.sync

# Saves the data
change_set_persister = ChangeSetPersister.new(
  metadata_adapter: Valkyrie.config.metadata_adapter,
  storage_adapter: Valkyrie.config.storage_adapter
)
updated_resource = change_set_persister.save(change_set: change_set)

Incrementally changing a property

change_set = MyChangeSet.new(resource)
change_set.member_ids << '1'
# optional, if you know the field doesn't need to be validated
change_set.validate(member_ids: change_set.member_ids)
change_set.sync

change_set_persister = ChangeSetPersister.new(
  metadata_adapter: Valkyrie.config.metadata_adapter,
  storage_adapter: Valkyrie.config.storage_adapter
)
updated_resource = change_set_persister.save(change_set: change_set)