How I Built a Simple Game via Ruby on Rails and Javascript

Written by scrabill | Published 2020/09/13
Tech Story Tags: ruby | ruby-on-rails | forms | single-page-web-applications | programm | video-game-development | game-development | javascript

TLDR A few months ago, I had the idea to build a simple game that functions something like this. I wanted to be able to add a player's name and their score to the leaderboard at the end of a game. The game mechanics changed in the early stages of building it in Ruby on Rails (Rails) and Javascript. We're anticipating that the data is successfully written to the server and responding right away. We can fake it on the frontend UI by pulling the name from the input field and displaying that.via the TL;DR App

A few months ago, I had the idea to build a simple game that functions something like this.
Above, An early, rough concept for the Food or Foe emoji game
The game mechanics changed in the early stages of building it in Ruby on Rails (Rails) and Javascript. One feature, I knew I wanted, was to be able to add a player's name and their score to the leaderboard at the end of a game.
Since a
User
has_many
Games
I wanted to be able to create a new
Game
instance at the same time as a
User
instance. If a
User
with the given name already exists, create the
Game
and associate it with that
User
.
Oh and this had to happen without reloading the page.

Was it possible?

Yes!
At first, I was overthinking how it might work on the frontend. Then, a classmate pointed out, that the creation of the
User
and
Game
could be handled on the backend, since the two were associated.
For this to happen, I need two pieces of data
The player’s name from the form input and their score
I could query the Document Object Model (DOM) for the input field with 
this.nameInput = document.querySelector("#name")
 and access it’s value with 
.value
. The score was being rendered on the frontend so I could access it in a similar fashion.
const body = {
      score: this.score.innerText,
      name: this.nameInput.value,
    }
Formatted as an object, I could pass it into the 
createGame()
 fetch request in 
GamesAdapters.js
.
 createGame(body) {
    return fetch(this.baseURL, {
      method: 'POST',
      headers: {
         'content-type': 'application/json'
      },
      body: JSON.stringify(body)
    })
    .then(res => res.json())
  }
Did I mention the page shouldn't reload either?
Luckily, that could be solved by including
e.preventDefault()
within the
createGame()
function that is triggered by the form submission button.
createGame(e) {
    console.log("Saving the game...")

    e.preventDefault()
    
    const body = {
      score: this.score.innerText,
      name: this.nameInput.value,
    }

    this.adapter.createGame(body)

  }

Rendering the New Score

The POST
fetch()
request created a new record and returns the record object, which looks something like this.
#<Game id: 85, user_id: 1, score: 37, created_at: "2020-02-24 00:25:42", updated_at: "2020-02-24 00:25:42">
Oh no.
I see a user_id. Within Rails. It's possible to get a Users name from their ID, but is there a way to access it on the front end without a page reload?
There is, but it would require a page reload, which we want to avoid for this project. But, we can fake it on the frontend UI by pulling the name from the input field and displaying that. Let's add a
.then
statement to the end of
createGame(e)
to handle this.
createGame(e) {
    console.log("Saving the game...")

    e.preventDefault()

    const body = {
      score: this.score.innerText,
      name: this.nameInput.value,
    }

    this.adapter.createGame(body)

    .then(game => {
      let gameObject = `<li>${game.score} - ${this.nameInput.value}</li>`
      this.leaderboard.innerHTML += gameObject
      this.nameInput.value = ""
    })

  }
Our leaderboard, now looks something like this.
A 3rd player and their score has been added to the leaderboard

If we were to refresh/reload the page, visually, we would not see anything different. This is an example of an optimistic user interface. We're anticipating that the data is successfully written to the server and are responding right away by displaying the data. We'll also clear out the input field when we're done, to mimic what would happen if there were a page refresh.

Written by scrabill | Front End Software Engineer
Published by HackerNoon on 2020/09/13