-
Notifications
You must be signed in to change notification settings - Fork 23
Persisting changes through synchronization
- Understand persisting data with Change Sets.
- Create a Book resource, then:
- Create/associate a Change Set with it.
- Persist the changes to the book by syncing the Change Set.
- Describe common problems
The basic process it to...
- create a change set passing in a resource
- This copies in values from the resource to the change set when resource attribute name and change set property name match.
- make changes to values in the change set
- validate changes (More information on this later in Defining change set validations. Examples in this lesson do not show validating.)
- sync changes in change set back to the resource
- persist the resource using a Valkyrie persister
Run all examples in rails console...
Create a changeset and update:
book = Book.new
book_cs = BookChangeSet.new(book)
book_cs.changed? # false
book_cs.title = "Ender's Game" # update title in the change set
book_cs.changed? # true - tests if anything has changed
book_cs.changed? :title # true - tests if the title changed
book_cs.changed? :author # false - tests if the author changed
book_cs.author = "Orson Scott Card"
book_cs.series = "Enderverse"
Update values in the resource:
book.title # [] # the book resource remains unchanged at this point
book_cs.sync # copies values from changeset to resource
book.title # ["Ender's Game"] # book is updated after sync
book.persisted? # false - book is not yet in the database because it was created above
Save the updated values in the resource:
book_cs.save # raise no NoMethodError
pg_persister.save(resource: book) # use persister to save resource after syncing
book.persisted? # true - book was created in the database by the persister
Related resource attribute definition:
attribute :author, Valkyrie::Types::Set.of(Valkyrie::Types::Strict::String).meta(ordered: true)
Property definition being tests:
property :author, multiple: true, required: true
Impact of required: true
:
book = Book.new
book_cs = BookChangeSet.new(book)
book_cs.title = "Ender's Game" # update title in the change set
book_cs.series = "Enderverse"
book_cs.sync
You might expect this to fail because author is required, but not set. The required option does not enforce presence. We will see how to enforce presence in Defining change set validations.
So what does required do? It allows you to ask the change set if a property is required.
book_cs.required? :author # true
book_cs.required? :series # false
Related resource attribute definition:
attribute :series, Valkyrie::Types::Strict::String
Property definition being tests:
property :series, multiple: false, required: false
Impact of Strict::String
:
book = Book.new
book_cs = BookChangeSet.new(book)
book_cs.sync
Gets error:
1: from (eval):2:in `series='
Dry::Types::ConstraintError (nil violates constraints (type?(String, nil) failed))
Series is intended to not be required. But if you use a Strict type, it will fail if the value is nil.
If you want a Strict type to allow nil, add optional
to the type definition in the resource.
attribute :series, Valkyrie::Types::Strict::String.optional
Changesets respond to #save
method, but Valkyrie does not support this.
book = Book.new
book_cs = BookChangeSet.new(book)
book_cs.title = "Ender's Game" # update title in the change set
book_cs.author = "Orson Scott Card"
book_cs.series = "Enderverse"
book_cs.save
Gets error:
NoMethodError (undefined method `save' for #<Book:...>)
Notice the error complains that save
is not defined on Book
, not on BookChangeSet
. This happens because resources do not support #save
. A persister is used to save resources.
The process to save changes is to sync
and persist
. See example under Successfully change and save for how to correctly save.