Skip to content

Persisting changes through synchronization

E. Lynette Rayle edited this page Oct 23, 2020 · 2 revisions

back to Introduction

Goals

  • 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

Persisting with Change Sets

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

SPOTCHECK

Run all examples in rails console...

Successfully change and save

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

Common GOTCHAS

required option not enforced

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

Strict value missing raises error

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

save through change set raises error

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.

Previous | Next