-
Notifications
You must be signed in to change notification settings - Fork 30
Lesson Generate Rails Scaffolding for Creating and Editing Books
- 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
This lesson walks you through modifying the "Author" field in your book 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.
We will use the Rails scaffold generator to set up the routes, Controller and Views we need in order to CRUD books.
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 Book model and make it assume books have title
and author
attributes like the ones we set up earlier in Lesson Build a book model with RDF.
rails generate scaffold Book title:string author:string
NOTE: If you completed the XML based Codex example instead of the RDF based Book example earlier, all you need to do is replace
Book
withCodex
in the line above.
When it asks you whether to overwrite app/models/book.rb
, enter n
and hit enter.
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 books. We're using Fedora, not SQL, to persist our book 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/20130417230046_create_books.rb
Run the rails server
and visit http://localhost:3000/books
Explore the pages for creating, editing and showing Books.
git add .
git commit -m "Ran Book scaffold generator"
Open app/models/book.rb
and edit the multiple setting to be 'true':
property :author, predicate: ::RDF::DC.creator, multiple: true
NOTE: you might be editing the file
app/models/codex.rb
if you completed the XML step of the tutorial, just make sure the value formultiple:
in the author property is set totrue
Now you need to tell your hydra application how to display multivalued fields in the 'show' (Display) view for this model.
In app/views/books/show.html.erb
find the lines that display the author field.
<p>
<strong>Author:</strong>
<%= @book.author %>
</p>
We want to make these lines iterate over the values returned by @book.author
and put them in a list
<p>
<strong>Author(s):</strong>
<ul>
<% @book.author.each do |author|%>
<li><%= author %></li>
<% end %>
</ul>
</p>
Save the file and refresh the Show view for a book. Now authors show up as a list of values. Note that the display of results of a search is not affected, only the view which you can reach from http://localhost:3000/books.
The _form
partial defines the guts of the form that's 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/books/_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 @book.author
and displays a text_field tag for each of them. Note that the @name attribute will be set to "book[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" %>
<% @book.author.each do |author| %>
<div class="field">
<%= text_field_tag "book[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" %>
<% @book.author.each do |author| %>
<div class="field">
<%= text_field_tag "book[author][]", author %>
</div>
<% end %>
<div class="field">
<%= text_field_tag "book[author][]", nil %>
</div>
Update the book_params
method in app/controllers/books_controller.rb
from
def book_params
params.require(:book).permit(:title, :author)
end
to
def book_params
params.require(:book).permit(:title, :author=>[])
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 BooksController to not save authors that don't have names.
# app/controllers/books_controller.rb
def update
@book.attributes = book_params
@book.author = params[:book][:author].select { |a| a.present? }
respond_to do |format|
if @book.save
format.html { redirect_to @book, notice: 'Book was successfully updated.' }
format.json { render :show, status: :ok, location: @book }
else
format.html { render :edit }
format.json { render json: @book.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 Book. That goes beyond the scope of this tutorial because it requires javascript (or a multi-page workflow).
Start up the rails console and run the following commands to add a second author to our book.
b = Book.find('test-1')
b.author += ['Some other author']
b.save
Visit http://localhost:3000/books again and see that multiple authors show up and that you can edit them.
git add .
git commit -m "Handling multivalued author 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.
Proceed to additional hydra tutorials including Tame your RDF Metadata with ActiveFedora Tame Your XML With OM and Access Controls with Hydra or go back to explore other [Dive into Hydra](Dive into Hydra#bonus) tutorial bonus lessons.