Skip to content

Creating relationships between resources

E. Lynette Rayle edited this page Oct 22, 2020 · 4 revisions

back to Introduction

Goals

  • Create relationships between resources using member_ids.
  • Create a relationship by including a full resource in another resource.

Create resources and assign them as members of another resource

In this step we will make page resources members of the book resource. Normally, you would save the pages before making them a member of another resource. As a side effect of saving, an id will be assigned to the pages.

info_16 As a general good practice, DON'T assign ids. We assign ids in the example below only to demonstrate how member_ids works before we'd discussed persistence of resources which will generate IDs.
warning_16 For some persistence adapters, assigning an ID ok acceptable and they will use the assigned id. But for others, they have their own way of assigning IDs to address defined behaviors in the adapter's backing data source (e.g. Postgres) as in primary key constraints, and so it is appropriate to delegate this action to the adapter on save.

You can assign alternate_ids if an attribute for alternate_ids is defined in the resource definition. As an example, Hyrax uses alternate ids to hold the GUIDs created separately by the Hyrax system and which are used as part of the URL for accessing items.

> page1 = Page.new
> page1.id = "page_1"          
  => "page_1"
> page1.id                     
 => #<Valkyrie::ID:... @id="page_1">
> page2 = Page.new(id: "page_2")
> page3 = Page.new(id: "page_3")

Assigning member_ids allow operators similar to those supported by Arrays.

> book = Book.new
> book.member_ids = page1.id   
 => #<Valkyrie::ID:... @id="page_1">
> book.member_ids
 => [#<Valkyrie::ID:... @id="page_1">]
> book.member_ids << page2.id  
 => [#<Valkyrie::ID:... @id="page_1">, #<Valkyrie::ID:... @id="page_2">]
> book.member_ids += [page3.id]     
 => [#<Valkyrie::ID:... @id="page_1">, #<Valkyrie::ID:... @id="page_2">, #<Valkyrie::ID:... @id="page_3">]

Include a full resource in another resource

Create a cover art resource for the book.

> cover_art = CoverArt.new(id: 'cover_art1', alternate_ids: 'ca1', artists: 'Mary GrandPré')
 => #<CoverArt id=nil internal_resource="CoverArt" created_at=nil updated_at=nil new_record=true alternate_ids=[#<Valkyrie::ID:... @id="ca1">] artists=["Mary GrandPré"] image_id=nil>

Let's try and assign the cover art the same way we did member_ids. Notice that it tries to coerce the cover art's id into an instance of CoverArt and raises an exception when it fails.

> book.cover_art = cover_art.id
 => Dry::Struct::Error ([CoverArt.new] can't convert Valkyrie::ID into Hash)

When correctly setting the cover art on the book resource, the entire object is copied into the book resource.

> book.cover_art = cover_art
> book.cover_art
 => [#<CoverArt id='cover_art1' internal_resource="CoverArt" created_at=nil updated_at=nil new_record=true alternate_ids=[#<Valkyrie::ID:... @id="ca1">] artists=["Mary GrandPré"] image_id=nil>]

One last thing to notice, updating the cover_art resource also updates cover_art in the book.

> book.cover_art.first.artists # BEFORE the update
 => ["Mary GrandPré"]

> cover_art.artists += ["Kazu Kibuishi", "Brian Selznick"]
# ["Mary GrandPré", "Kazu Kibuishi", "Brian Selznick"]

Reflected in the book...

> book.cover_art.first.artists # AFTER the update
 => ["Mary GrandPré", "Kazu Kibuishi", "Brian Selznick"]

Potential advanced exercise: How would you update a specific cover_art resource saved in the book's Array of cover_art resources?


Previous | Next