Lesson: Generate Rails Scaffolding for Creating and Editing - samvera/hydra-works GitHub Wiki

Goals

  • Understand the difference between unique (single-value) and multi-valued metadata fields
  • Learn how to make modifications to the views which support CRUD (Create, Read, Update, Delete) on objects in your repo

Explanation

This lesson walks you through modifying setting up scaffolding for the models. Next it shows you how to the modify the "Author" field in your bibliographic_work model to make it either single- or multi-valued. The lesson then walks through the changes necessary to modify views to read, create, and edit your updated metadata model.

Steps

Step 1: Set up Rails Scaffolding for creating and editing for our models

We will use the Rails scaffold generator to set up the routes, Controller and Views we need in order to CRUD for the models we created.

NOTE: If you are not familiar with the ideas of Controllers, Views and routes, or aren't familiar with the Rails scaffold generator, go through the Railsbridge Curriculum and then come back to this lesson. You might also want to read the Getting Started with Rails guide.

Tell the generator to build scaffolding for the each of the models we created in Lesson: Define models with Hydra-Works and make them have attributes for each property we defined in the models. Execute the following commands in the terminal window.

rails generate scaffold Collection title:string
rails generate scaffold BibliographicWork title:string author:string abstract
rails generate scaffold BibliographicFileSet title:string
rails generate scaffold PageFileSet page_number:integer

warning Warning: Type n when asked whether you want to overwrite app/models/collection.rb, app/models/bibliographic_work.rb, app/models/bibliographic_file_set.rb, and app/models/page_file_set.rb. If you simply hit return, the default is Y. If you accidentally hit return, you can copy the model code back from the final version of it in Lesson: Explore Objects in Fedora and Solr (Step 6) or Lesson: Add pages to a bibliographic work.

Rails assumes that you're using an ActiveRecord based model stored in a SQL databases and creates the necessary database migrations to setup a table to store bibliographic_works. We're using Fedora, not SQL, to persist our bibliographic_work objects, so you don't need this database migration. You can delete it with the git clean command.

git clean -df db

You'll see output something like this:

Removing db/migrate/20150925124032_create_collections.rb
Removing db/migrate/20150925124045_create_bibliographic_works.rb
Removing db/migrate/20150925124124_create_bibliographic_file_sets.rb
Removing db/migrate/20150925124153_create_page_file_sets.rb

Step 2: Run the server & Explore

Run the rails server and visit pages...

Explore the pages for creating, editing and showing for each model. You may want to do the next step before doing a lot of exploring.

Step 3: Make lists easier to read

The default stylesheet has all the fields and the action buttons at the end of the set of fields run together. Not very pretty. Let's make a quick, albeit inelegant, css update just to make things readable.

Edit app/assets/stylesheets/application.css and append the following to the end of the file.

td {
    padding: 10px;
    border: gray 1px solid;
}

NOTE: Blacklight uses Bootstrap for controlling its styles. If you want to learn how to customize styles and code for Blacklight, see the Customizing Blacklight Tutorial presented at Hydra Connect 2015.

Start the rails server up and take another peak at one of the index views listed at the start of this previous step. At least things are readable now if not pretty.

Commit your work...

git add .
git commit -m "Ran model scaffold generators"

Step 4: Make the Display view show Authors as a multi-valued field

Open app/models/bibliographic_work.rb and edit the multiple setting to be 'true':

  property :author, predicate: ::RDF::DC.creator, multiple: true do |index|

Now you need to tell your hydra application how to display multivalued fields in the 'show' (Display) view for this model.

In app/views/bibliographic_works/show.html.erb find the lines that display the author field.

<p>
  <strong>Author:</strong>
  <%= @bibliographic_work.author %>
</p>

Change these lines to match below. This will iterate over the values returned by @bibliographic_work.author and put them in a list

<p>
  <strong>Author(s):</strong>
  <ul>
    <% @bibliographic_work.author.each do |author|%>
      <li><%= author %></li>
    <% end %>
  </ul>
</p>

Save the file and refresh the Show view for a bibliographic_work. Now authors show up as a list of values.

NOTE: The display of results of a search is not affected, only the view which you can reach from http://localhost:3000/bibliographic_works.

Step 5: Allow Create and Update views to display Authors as a multi-valued field

The _form partial defines the guts of the form that is used in both the new (Create) view and the edit (Update) view. That makes our lives simpler because we only have to update that one file to fix both pages!

In app/views/bibliographic_works/_form.html.erb find the lines that display the author field.

<div class="field">
    <%= f.label :author %><br />
    <%= f.text_field :author %>
</div>

Replace those lines with something that iterates over the values from @bibliographic_work.author and displays a text_field tag for each of them.

NOTE: The @name attribute will be set to "bibliographic_work[author][]". The trailing [] in the name tells Rails that this is a multivalued field that should be parsed as an Array.

  <%= f.label :author, "Authors" %>
  <% @bibliographic_work.author.each do |author| %>
    <div class="field">
      <%= text_field_tag "bibliographic_work[author][]", author %>
    </div>
  <% end %> 

This handles displaying existing author values, but what about setting the author value in the first place? If there are no values in the array, no fields are going to be displayed. As a stop-gap, we can add a conditional clause that displays an empty text_field after the existing authors are displayed.

  <%= f.label :author, "Authors" %>
  <% @bibliographic_work.author.each do |author| %>
    <div class="field">
      <%= text_field_tag "bibliographic_work[author][]", author %>
    </div>
  <% end %> 
  <div class="field">
    <%= text_field_tag "bibliographic_work[author][]", nil %>
  </div>

Update the bibliographic_work_params method in app/controllers/bibliographic_works_controller.rb from

    def bibliographic_work_params
      params.require(:bibliographic_work).permit(:title, :author, :abstract)
    end

to

    def bibliographic_work_params
      params.require(:bibliographic_work).permit(:title, :author=>[], :abstract=>'')
    end

Now every time you save the form you'll get one more additional author. However you get this author even if you haven't filled any value in. Let's update the BibliographWorksController to not save authors that don't have names.

Edit app/controllers/bibliographic_works_controller.rb and modify the #update method to match the following.

  def update
    @bibliographic_work.attributes = bibliographic_work_params
    @bibliographic_work.author = params[:bibliographic_work][:author].select { |a| a.present? }
    respond_to do |format|
      if @bibliographic_work.save
        format.html { redirect_to @bibliographic_work, notice: 'Bibliographic Work was successfully updated.' }
        format.json { render :show, status: :ok, location: @bibliographic_work }
      else
        format.html { render :edit }
        format.json { render json: @bibliographic_work.errors, status: :unprocessable_entity }
      end
    end
  end

NOTE: This still doesn't cover the case where you want to add more than one additional Author to a Bibliographic Work. That goes beyond the scope of this tutorial because it requires javascript (or a multi-page workflow).

Step 6: Try out multiple authors

Start up the rails console and run the following commands to add a second author to our bibliographic_work.

bw = BibliographicWork.find('work-1')
bw.author += ['Some other author']
bw.save

Start up the rails server and visit http://localhost:3000/bibliographic_works again and see that multiple authors show up and that you can edit them.

Commit your work...

git add .
git commit -m "Handling multivalued author fields"

Step 7: [Optional] Enhance the display of Title fields

Based on the concepts in steps 1-7, determine whether you want 'Title' to display as a single or multi-valued field and make appropriate edits to the 'show' view and '_form' partial on your own.

In general, you might not want to build all the views to edit your metadata by hand. The hydra-editor gem is used by many hydra adopters as a way to handle providing metadata editing forms without having to hand-code for each field. It also provides javascript support for repeating fields like our author field above so you can add multiple values to a single term without having to save each time.

Step 8: Update the home page for Blacklight to give access to our show pages

Edit (or create) app/views/catalog/_home_text.html.erb and set it to...

NOTE: If creating, you may need to create the catalog directory if it doesn't exist.

<h4>Browse...</h4>
<ul>
  <li><%= link_to 'Collections', collections_path %></li>
  <li><%= link_to 'Works', bibliographic_works_path %></li>
</ul>

NOTE: I'm choosing to only allow browsing at the collection and work level. The only way to access files is through the work. We'll set that up in a few steps. We could have decided that users always have to start at collections and drill down to works, in which case, we would only have Browse Collections.

NOTE: You might be interested in checking out the hydra-collections gem which provides utilities and controllers for working with collections.

Start up the rails server and visit http://localhost:3000/ and see that you now have choices for browsing from the home page.

Commit your work...

git add .
git commit -m "Browsing from home page"

Step 9: Make a simple drill down navigation scheme from Collections to their Works

Let's update the show page for collections to list works in the displayed collection. Edit app/views/collections/show.html.erb.

Add the following at the top of the file, just under the notice.

<h1>Collection</h1>

Add the following to the end to get the listing of works in the collection.

<hr>
<h5>Listing Bibliographic Works in this Collection</h5>

<table>
  <thead>
  <tr>
    <th>Title</th>
    <th>Author</th>
    <th>Abstract</th>
    <th colspan="3"></th>
  </tr>
  </thead>

  <tbody>
  <% @collection.works.each do |bibliographic_work| %>
      <tr>
        <td><%= bibliographic_work.title %></td>
        <td><%= bibliographic_work.author %></td>
        <td><%= bibliographic_work.abstract %></td>
        <td><%= link_to 'Show', bibliographic_work %></td>
        <td><%= link_to 'Edit', edit_bibliographic_work_path(bibliographic_work) %></td>
        <td><%= link_to 'Destroy', bibliographic_work, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
  <% end %>
  </tbody>
</table>

NOTE: The code listed here is the same code in app/views/bibliographic_works/index.html.erb with some slight wording and style changes. There are only two changes, 1) change the 'Listing' heading to a smaller heading tag and add that the works are 'in this Collection', 2) get the list of bibliographic_works from @collection.generic_works.

Try it out...

  • Start rails server
  • Goto http://localhost:3000/. You should see Browse... followed by Collections and Works.
  • Click Collections link under Browse...
  • Click show link next to Works by Edgar Allan Poe. You should see the title of the collection and the list of works in that collection.

Step 11: Make a simple drill down navigation scheme from Works to their Files

Let's update the show page for works to list files in the displayed work. Edit app/views/bibliographic_works/show.html.erb.

Add the following at the top of the file, just under the notice.

<h1>Bibliographic Work</h1>

Add the following to the end to get the listing of files in the work.

<hr>
<h5>Listing Files in this Bibliographic Work</h5>

<table>
  <thead>
  <tr>
    <th>Title/Page Number</th>
    <th colspan="3"></th>
  </tr>
  </thead>

  <tbody>
  <% @bibliographic_work.file_sets.each do |fs| %>
      <% if fs.is_a? PageFileSet %>
      <tr>
        <td>page <%= fs.page_number %></td>
        <td><%= link_to 'Show', fs %></td>
        <td><%= link_to 'Edit', edit_page_file_set_path(fs) %></td>
        <td><%= link_to 'Destroy', fs, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
      <% else %>
      <tr>
        <td><%= fs.title %></td>
        <td><%= link_to 'Show', fs %></td>
        <td><%= link_to 'Edit', edit_bibliographic_file_set_path(fs) %></td>
        <td><%= link_to 'Destroy', fs, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
      <% end %>
  <% end %>
  </tbody>
</table>

NOTE: The code listed here is the basically the same code in app/views/bibliographic_file_sets/index.html.erb merged with app/views/page_file_sets/index.html.erb and including some slight wording and style changes. There are only two changes, 1) change the 'Listing' heading to a smaller heading tag and add that the files are 'in this Bibliographic Work', 2) get the list of bibliographic_file_sets and page_file_sets from @collection.generic_files.

You may also want to add headers to the top of the show pages for the file models. Edit app/views/bibliographic_file_sets/show.html.erb and add <h1>Bibliographic File</h1> just under the notice. Edit app/views/page_file_sets/show.html.erb and add <h1>Page File</h1> just under the notice.

Try it out...

  • Goto http://localhost:3000/. You should see Browse... followed by Collections and Works.
  • Click Collections link under Browse...
  • Click show link next to Works by by Edgar Allan Poe. You should see the title of the collection and the list of works in that collection.
  • Click the show link next to The Raven to see the list of files in that work. You should see the PDF file for the entire book and several page files.
  • Click the show link next to any of the files to see the show page for that file.

NOTE: We didn't make the Back buttons smarter, so using the back button (on the page, not the browser's back button) from a work will show all works instead of returning to the collection's show page. Fixing this is beyond the scope of this tutorial.

Commit your work...

git add .
git commit -m "Drilling down from Collection to Work to File"

Next Step

This completes the basic and bonus lessons for Dive into Hydra-Works. Great job! Go back to [Dive into Hydra-Works](Dive into Hydra#Next Steps) tutorial to learn about more steps you can take to expand your knowledge of Hydra-Works.

⚠️ **GitHub.com Fallback** ⚠️