Skip to content
No description, website, or topics provided.
JavaScript Ruby CSS HTML CoffeeScript
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Giles live

Giles is a personal library management app inspired by Libib and named after Buffy the Vampire Slayer's book-loving Watcher. Giles is a single-page web app built with Ruby on Rails on the backend, a PostgreSQL database, and React/Redux frontend architecture.


Does the idea of mixing your books with your significant other's fill you with anxiety? Do half of your books live in your parents' basement? Want to catalog your sci-fi collection separately from your college philosophy texts?

With Giles, create a library for any group of books you'd like to keep track of. Adding books to a library is simple--Giles can search the GoogleBooks API by ISBN or keyword, or you can manually enter your book in a simple form.

User Auth

Backend user authentication utilizes BCrypt for password-hashing and password-hash-matching upon login. The current user is bootstrapped to the frontend, allowing the user to remain logged in despite a page refresh.

<script type="text/javascript">
  <% if logged_in? %>
  	window.currentUser =
      <%= render("api/users/user.json.jbuilder", user: current_user).html_safe %>
  <% end %>


Libraries are implemented very simply on the server side; each library belongs to a user and has many book_shelvings, through which it is connected to its books. On the frontend, all of a user's libraries are fetched from the backend via AJAX request upon login. The first library's books are fetched by default, and other libraries' books are fetched as the user selects that library from a dropdown menu.

Giles relies on a custom middleware to save the current library and its books to localStorage. This saved information is passed to the Redux store as preloadedState, allowing Giles to remember which library a user was accessing in the event of a page refresh.

export const localStorageMiddleware = store => {
  return next => action => {

    switch (action.type) {
          libraries: {
            entities: store.getState().libraries.entities,
          books: action.books

      ...more cases

    return next(action);


Books added through a GoogleBooks API search behave a little bit differently than those added manually by a user. Users can edit a manually-added book's data, whereas books added through search are not editable. This is enforced on the front-end by disabling the 'edit' button for API-originated books and on the backend by checking the book's editable attribute in the controller's update action.

The API search generally returns a link to the book's cover art hosted on GoogleBooks, which is stored in a remote_image_url column. Users can upload cover images for books they add manually; the attachments are handled by Paperclip (a Ruby gem) and hosted by Amazon Web Services. The frontend BookDetail component renders the cover image conditionally; if the book has a remote image, that one is rendered, otherwise the uploaded image (or a default icon if no image was uploaded) renders.

book index item

Library Search

Users search the current library by typing in the search bar; an onChange handler in the search bar component--

handleChange(e) {
    { searchTerm: e.currentTarget.value },
    () => this.props.initiateSearch(this.state.searchTerm)

--dispatches initiateSearch, which is "caught" by thunk middleware, filters the books currently in frontend state by the search term, and dispatches displaySearchResults:

export const initiateSearch = term => {
  return (dispatch, getState) => {
    const books = booksArray(getState().books);
    const results = bookSearch(books, term);

    dispatch(displaySearchResults(results, term));

This results in nearly-instantaneous updates to search results as the user types.

Features of the Future

I personally have a lot of books, and a lot of thoughts about how I'd like to manage them. I look forward to growing Giles beyond this core functionality in the future, and am looking forward to implementing:

Comprehensive Search

Currently, Giles can search the current library for title / author matches. I would like to implement a comprehensive database search of all libraries with advanced selectors.

Notes and Tags

Users will be able to add notes and tags to all books, regardless of origin.

Data Visualization

Giles will have a dashboard to help users better visualize their libraries--how many 19th century novels do you have? What percentage of your collection lives in that "Mom's Basement" library?

You can’t perform that action at this time.