Rails and JavaScript
Tags: ruby, rails, javascript, spa
Published: 2021-09-20 14:19:16

# Guitar Picks 
I wrote a simple single page application (SPA) that utilizes HTML, CSS, and JavaScript for the front-end and a Ruby on Rails acting as an API server. For this project I went with the concept of a photo sharing site for guitarists which I aptly named *Guitar Picks*.

The app works quite simply by requesting a *username* to get started. Once a valid username has been accepted, the main content of the page is written using JavaScript to show the current list of guitars through a series of function calls, one of which is a request to the server to grab the Guitars table and which is render to JSON.

## Rendering JSON data
The following snippet is a get request from the front-end to the back-end and is targeting `this.api` followed by the route to populate data for the `Guitar` class constructor.
```JavaScript
getGuitars = () => {
    return fetch(this.api + "/guitars")
    .then(response => response.json())
  }
```
This function is called when a valid username is accepted and processes the `api` call, setting an empty array for `Guitar.all`, then finishing by sending that infomation one-by-one to a render method to produce the output on screen, all without a page refresh.
```JavaScript
static getGuitars = () => {
    api.getGuitars().then(guitars => {
      Guitar.all = []
      guitars.forEach(guitar => new Guitar(guitar))
      this.renderGuitars()
    })
  }
```
## Front-end troubles
A few issues that I faced with this concept was how to render updated information such as when a user deletes a post of a guitar. The guitar is stored in the array `Guitar.all`, but without updating this array, would produce the guitar until the page was refreshed or what I have done (per requirement of this project) since this is a SPA and page refreshes are not allowed. By calling `Guitar.getGuitars()` keeps the JSON data from the back-end in sync with the front-end without the need for a page refresh.

I learned quickly that any script that is written needs to be referenced in the `HTML` using a `<script>` tag in order to be read. I faced some headaches not grasping this concept at the start as with Rails was not an issues as all the files where being read as they were needed. That's the first place to look to trouble-shoot code not running and verifying the the `src` is targeting the correct location of said script file.

## Rails back-end setup
Setting up a rails server in this manner was fairly straight forward. Starting with `rails new server_name --api`. With the `--api` flag this tells Rails to only generate files which are dependent to serving data rather than taking advantage of `views` and `erb` files that would normally do the rendering of on-screen information. `Controllers` are similar to writing `Ruby` code with the change-off of instead of using a `redirect`, one would write `render json:`. A view would grab the instance variable from the controller and do something with it while the `render json:` would do just that. By going to the route in a browser, with the Rails server running, http://localhost:3000/guitars will only produce a JSON object with the data stored in the current database.
```JavaScript
def show
    guitar = Guitar.find_by(id: params[:id])
    if guitar
      render json: guitar
    else
      render json: { message: "No guitars found" }
    end
  end
```
Add in an `if else` block and if a guitar `id` does not exist will produce a message to state that there is no information stored at the location.

### Rails Models
As for models using the `--api` flag, work just the same as one would expect if any validations or associations are given.

### Serializers
Using a `serializer` for this type of project seems almost necessary in order to keep the app DRY (Do not Repeat Yourself). The `serializer` is used to keep the information that is produced in the JSON object formalized and shows reduced information if required. It can also be used to add custom serialized information to bring information in from an associated object from another Class.
```JavaScript
class GuitarSerializer < ActiveModel::Serializer
  attributes :id, :style, :brand, :model, :image_url, :username, :created_at

  def username 
    self.object.user.username
  end

  def created_at
    self.object.created_at.strftime("%b-%d-%Y")
  end
end
```
The `Guitar` class had a `belongs_to` relationship to `User`, but did not have an attribute of `username`. By creating a custom method to tell the `serializer` to find the `username` of the `user` object associated with it. Another thing learned from this project was date formatting in the `serializer` worked better if formatted for the data here rather than the whole object. This allows the front-end code to grab the date as-is and be printed directly to the DOM. 

The serialized data can then be used in functions where applicable and destructured for ease of use in render functions.