Restaurant Explorer - Project Page

Project Release Date:

Introduction

As part of the Flatiron School curriculum, I am producing small, self-contained projects that highlight core skills and solutions to common web development challenges. This project - Restaurant Explorer - aims to build a Rails back-end, serialize data as json, and use a javascript front-end to present it dynamically to a user.

The Challenge

There were a few challenges to this project. First, I wanted to build on my previous Rails skills. Although the project requirements didn’t specify things like secure user accounts, complex data relationships, validation, or named scopes, I wanted to take the opportunity to reinforce those areas in this project. Next, I wanted my project to be functional and attractive - which meant not skipping on the design. I got an opportunity to use the asset pipeline to load Bootstrap 4 and write a little bit of Sass to spruce up the look & feel of my project. Finally, the main challenge of the project was to walk from Rails to Javascript via the serialization process using Active Model Serializers.

The Solution

The result for my portfolio project is for website that allows users to explorer and comment on a set of restaurants - in the mold of a Yelp-type website. The website allows users to view detailed information about individual restaurants and page backwards and forwards through the list of all restaurants. Finally, the detail page for an individual restaurant includes user comments associated with each restaurant. A signed-in user can add new comments - displayed immediately upon submission.

Users can sign-up for a new account and log in and out with an existing account. Only signed in users are able to add new comments, but any visitors can view existing comments made by other users.

Additional features include the incorporation of the Bootstrap 4 front-end component library, Font-Awesome icons, and royalty free images from Pexels.com.

Restaurant Explorer - Project Website

Restaurant Explorer - Project Website

Requirements

The following requirements formed the baseline of functionality for the initial release of the project.

  • Must have a Rails Backend
  • Makes use of ES6 features
  • Must translate the JSON responses into Javascript Model Objects
  • Must render at least one index page via JavaScript and an Active Model Serialization JSON Backend
  • Must render at least one show page via JavaScript and an Active Model Serialization JSON Backend
  • Your Rails application must reveal at least one has-many relationship through JSON that is then rendered to the page
  • Must use your Rails application to render a form for creating a resource that is submitted dynamically through JavaScript
  • At least one of the JS Model Objects must have a method on the prototype

UX Design

Although I didn’t undertake a full-fledged UX process for this project, some design planning was important and useful. I was thinking of the design in conjunction with the information architecture of the website - and they often can compliment each other during the planning process of a project.

Wireframes

The main aspect of UX Design for this project was creating wireframes that laid out the page organization and element spacing. Using Bootstrap 4 allowed me to take advantage of many of their components - like navbars and cards - to plan my design. I produced three wireframes for the major sections of the project - the home page, the restaurant list page, and the restaurant detail page.

Wireframe - Home Page

Wireframe - Home Page

Wireframe - List Page

Wireframe - List Page

Wireframe - Detail Page

Wireframe - Detail Page

The colors and typography for the website weren’t as important - and the Bootstrap 4 defaults for each worked well for this project.

Information Architecture

For this project, the website structure consisted of just a few pages:

  • Home page
  • Page listing all restaurants
  • Pages with details for each restaurant
  • About page
  • Login page
  • Sign-up page
  • User information page

Development

The point of the project is, of course, the skills shown in the development phase. The areas of notable development were the database, the data serializing with Active Model Serializer and the front-end processing via JavaScript.

Database

The data model for the project included several tables - as described below in the project entity relationship diagram (ERD). The focal database table for the project is the Restaurants table. From this table is a many-to-one relationship with the Comments table. Users are also attached to a restaurant via comments. I also made use of look-up tables for locations and a many-to-many table for possible cuisines each restaurant offered.

Entity Relationship Diagram

Entity Relationship Diagram

Active Model Serializers

An essential aspect of this portfolio project was to expose the data via json. To achieve this, I made use of the Active Model Serializers gem. In it’s basic usage - an active model serializer is great for serializing database content, especially content that is built with relational content. Setting up serialization was as easy as generating a serializer for a model and defining the associations that needed to be serialized.

class RestaurantSerializer < ActiveModel::Serializer
  attributes :id, :name, :description, :phone, :email, :image_url
  belongs_to :location
  has_many :cuisines
  has_many :comments, serializer: RestaurantCommentSerializer
end

In the example above, my Restaurants model had associations with the Locations, Cuisines, and Comments tables. And the Comments table had its own associations, which I also wanted to capture in my json output. In order to create the output, I utilized the respond_to block to execute the serializer and produce the json output.

def show
  @restaurant = Restaurant.find(params[:id])

  respond_to do |format|
    format.html { render :show }
    format.json { render json: @restaurant }
  end
end

JavaScript

The next challenge was to take the json content and work with it via Javascript. I took some time to fine tune my Javascript Model Objects. I decided to use the ES6 class syntax as the blueprint to build my objects. The main class I used was the Restaurant class. I also wrote a getter method to format a phone number. Finally, I created other methods and took advantage of ES6 template literals to output html with model content - as can be seen in the method singleHTML() below.

class Restaurant {
  constructor(obj) {
    this.id = obj.id;
    this.name = obj.name;
    this.description = obj.description;
    this._phone = obj.phone;
    this.email = obj.email;
    this.image = obj.image_url;
    this.location = obj.location.city;
    this.cuisines = obj.cuisines;
  }

  get phone() {
    var re = /\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})/g;
    var subst = "($1) $2-$3";
    return this._phone.replace(re, subst);
  }

    singleHTML() {
    return `
      <div class="card mb-3">
        <img id="restaurant-image" src="/assets/${
          this.image
        }" class="card-img-top" alt="${this.name}">
        <div class="card-body">
          <h5 id="restaurant-name-card" class="card-title">${this.name}</h5>
          <p id="restaurant-description" class="card-text">${
            this.description
          }</p>
          <div class="card-info-box">
          <div class="restaurant-contact">
            <p class="card-text mb-n1"><i class="fa fa-phone" style="color: black;"></i> <small class="text-muted">${
              this.phone
            }</small></p>
            <p class="card-text mb-n1"><i class="fa fa-envelope" style="color: black;"></i> <small class="text-muted">${
              this.email
            }</small></p>
            <p class="card-text"><i class="fa fa-map-marker" style="color: black;"></i> <small class="text-muted">${
              this.location
            }</small></p>
          </div>
          <div class="restaurant-cuisines">
          ${this.getCuisineNames(
            this.cuisines
          )} <p class="ml-1"><strong>Cuisines</strong>: </p>
          </div>
        </div>
      </div>
    `;
  }
}

To ease the interaction with the DOM, I made use of JQuery. This allowed for quick attachment/replacement of data to DOM elements. The website has minimal page refreshes, with most of the data needed for the page loaded and stored in variables.

Conclusion

This project was challenging - but not too challenging. The Rails curriculum content was great to prepare me for the rails-specific aspects of the project. I felt that in this project, I was able to produce some refined rails code. I feel more and more comfortable with rails concepts like validation, scoping, helper classes and methods, and more.

The Javascript portion of the project was also challenging. When working with Javascript in the past, I found that it was easy to write long functions that did everything within the single function call. This project has helped me work on skills like refactoring code, single responsibility principle (although I wasn’t 100% perfect at this), and adding meaning names and comments to my code. There are all skills I want to continue improving as I move forward.