Ruby, Active Record, Sinatra so much information so little time
Tags: sinatra, ruby, activerecord, crud
Published: 2023-01-30 17:12:28

# This is a Bootcamp
Attending a coding bootcamp is like drinking water through a fire hose. Don't believe me?  I prefer to write technically and there will be technical aspects in this post and things that were learned, however; I feel strongly that the comprehensive list that were were expected to learn over the last 3 weeks was just so incredible vast that the retention of the material is somewhere in the 30 - 40% range.

<div style="page-break-after: always;"></div>

Three weeks... one language cool as students that were already accustomed to the pace of the boot camp lifestyle of coding and lectures 12 hours a day for 6 weeks with JavaScript and React under our belts feeling confident after finishing front end projects that did feel incomplete because we have yet to learn a backend language the cohort was excited to dive into Ruby a back end language and tie the life of a full-stack software engineer together.  How I personally thought the phase was going to go ended up being quite the divergent path with slow progress learning a lot of small little steps and a lot of growing pains. 

<div style="page-break-after: always;"></div>

The divisions below are going to go into things that were learned in this project but it was not just Ruby.  In order to leverage the most in this phase we had to learn a few more tools. ActiveRecord, and Sinatra...

<div style="page-break-after: always;"></div>

# Phase 3 Ruby
Excited to learn ruby. What is Ruby? It was designed with an emphasis on programming productivity and simplicity. in Ruby everything is an object, that is how we started learning new syntax which was fairly straight forward, easy to read and easy to code:
<div style="page-break-after: always;"></div>
```
  def greet_programmer
    puts "Hello, programmer!"
  end

  def greet(name)
    puts "Hello, #{name}!"
  end

  def greet_with_default(name = "programmer")
    puts "Hello, #{name}!"
  end

  def add(num1, num2)
    num1 + num2
  end
```
<div style="page-break-after: always;"></div> 
A few simple methods with simple code. The puts command is a simple command in Ruby that just prints to the page.  Ruby has implicit returns that the line before the end is automatically returned in the method.  It seemed simple easy to read and easy to write.  Practicing the syntax learning the new language was a growing pain but that is a growing pain is with every new language. 

<div style="page-break-after: always;"></div> 

We were off to the races learning ruby writing methods and leveraging objects, everything that ruby promised us we would learn. 

<div style="page-break-after: always;"></div> 

#Active Record
This phase also gave us the incredible tool of Active Record.  Active record was powerful, gave us the ability to create database tables, create associations between those tables with the easy to learn macros (belongs_to and has_many) giving us methods we could use to leverage those associations in Ruby. We learned how to call class and instance methods on our databases on the back end through the use of rake console.

<div style="page-break-after: always;"></div>

Methods were working Associations were being made:
<div style="page-break-after: always;"></div>

```
class Team < ActiveRecord::Base
    belongs_to :owner
    has_many :players

    def drop(player_id)
        self.update(team_id: nil)
    end

    def homerun_count
        self.players.sum(&:homeruns)
    end

    def owner_name
        puts "#{self.owner.user_name}"
    end

end
```
<div style="page-break-after: always;"></div>
The above code would allow us to run association methods such as `Team.first.players` giving us all the players for the first team.  `Team.first.homerun_count` giving us all the homeruns for the first(given)team.
<div style="page-break-after: always;"></div>
All of this felt natural. Giving commands in the rake console methods are working properly and associations were made.
<div style="page-break-after: always;"></div>
Up to this point of the phase it was a lot of information we learned a lot of new things and were able to put an arsenal of skills in our brains that is our metaphorical bag of holding....
<div style="page-break-after: always;"></div>
# Project Week and learning Sinatra
I am going to start this segment with the metaphor my eyes were bigger than my stomach. 
<div style="page-break-after: always;"></div>
## Project introduction
The project idea was a simple fantasy sports baseball app where you could create a team and add or remove players from your team and the app would keep track of the number of homeruns for your team and update standings as you add or drop players or homeruns are increased.  
<div style="page-break-after: always;"></div>
Checklist

1. The frontend was updating state and puting data on the page.
2. The backend methods were created with Active Record and Ruby and were all working in the rake console.
3. ...Sinatra is where it all fell apart.
<div style="page-break-after: always;"></div>

## Sinatra Routing
 The frontend and the back end of our project were not communicating. Were we forgetting steps? Was the browser our own worst enemy? Cors error? Were the wrong gems installed?

<div style="page-break-after: always;"></div>

## installed gems in our Gemfile

gem 'sinatra'
gem 'activerecord', '~> 5.2'
gem 'sinatra-activerecord', :require => 'sinatra/activerecord'
gem 'rake'
gem 'require_all'
gem 'sqlite3'
gem 'thin'
gem 'shotgun'
gem 'pry'
gem 'bcrypt'
gem 'tux'
gem 'faker'
gem 'dotenv'
gem 'rack-cors'
gem 'rack-contrib'
gem 'rerun'

## Code in our config.ru

```
require './config/environment'

use Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :post, :delete, :put, :patch, :options, :head]
  end
end

use Rack::JSONBodyParser

use Rack::MethodOverride

if ActiveRecord::Base.connection.migration_context.needs_migration?
  raise 'Migrations are pending. Run `rake db:migrate` to resolve the issue.'
end

run ApplicationController
use OwnersController
use TeamsController
use PlayersController
```
 <div style="page-break-after: always;"></div>
Step by step and line by line we check boxes as we coded in config.ru to avoid getting errors. Was this enough lets find out.
<div style="page-break-after: always;"></div>
Our first Sinatra Route in our players controller:

```
  get "/players" do
    player = Player.all
    player.to_json
    
  end
```
Our fetch call on or React frontend Side:

```
useEffect(() => {
    const fetchData = async () => {
      try {
        const resp = await fetch("http://localhost:9292/players")
        const playersList = await resp.json()
        setPlayers(playersList)
      } catch (error) {
        alert(error)
      }
     }
  
     fetchData()
   
  }, [])
```
<div style="page-break-after: always;"></div>
...It worked!!!! after hours of wrestling with Sinatra to make sure we did everything correct we finally were getting our player database talking to our frontend and render information to the page. 
<div style="page-break-after: always;"></div>
later we changed the Sinatra route to 

```
 get "/players" do
    player = Player.all
    player.to_json(include: :team)
    
  end
```
and what the `(include: :team)` did was allow us to leverage the association between our players and teams table.  This unfortunately did not come until hours later when the information came to light that we could do that.
<div style="page-break-after: always;"></div>
For the week that was how the project went... slow coding a lot of research, find the answer, a lot of code, back down to  a crawl again and then back to research.  This loop repeated intensely all week with what sometimes felt backwards progress.

<div style="page-break-after: always;"></div>
## Table Associations in the project
Achieving full CRUD on one of our tables felt like a huge accomplishment. We had routes to Create, Read, Update and Destroy on our players table.  This felt like a victory however the power of the backend of ruby and active record was about being able to leverage associations which we had yet to achieve. This was the biggest hurdle to date so my talented partner Dylan Curtis and myself got to work rolled up with our sleeves and this is what we learned.
<div style="page-break-after: always;"></div>
### Adding and Dropping Players from the team

#### There is no place in ding dong city for you.
The main focus of our app was to leverage players on our teams to see who could project the most homeruns on the season. We needed to be able to create teams, add or remove players from our teams, add new players to be selected in the data base and finally update homeruns on our players.
we did that with CRUD actions. Fetch calls in React didn't change much but we did need to create correct routing in Sinatra to be able to communicate with our frontend.

<div style="page-break-after: always;"></div>

# CRUD

<div style="page-break-after: always;"></div>

## GET

```
 get "/players" do
    ply = Player.all
    ply.to_json(include: :team)
```
<div style="page-break-after: always;"></div>

## POST
Adding a player to the open roster. 

```
post "/players" do 

    ply = Player.create(first_name: params[:firstName],
      last_name: params[:lastName],
      player_number: params[:playerNumber],
      professional_team: params[:professionalTeam],
      position: params[:position],
      homeruns: 0,    
      team: nil,
      img_url: params[:imgURL])

    if ply.id
      halt 201, {ply: ply}.to_json
    else
      halt 400, {message: ply.errors.full_messages.to_sentence}.to_json
    end
  end
```
<div style="page-break-after: always;"></div>

## Patches 
### (we had 2 for this project and one did double duty)


```
patch "/players/:id/add_player" do
    player = Player.find_by(id: params[:id])
      if player 
         player.update(team_id: params[:team_id])
         halt 200, player.to_json(include: :team)
      else
        halt 400, player.errors.full_messages.to_sentence.to_json
       end      
      end
```

 and of corse we needed to add homeruns with our custom methods.

```
 patch "/players/:id/homerun" do    
    # binding.pry
    found_player = Player.find_by(id: params[:id]) 
   if found_player && found_player.add_homerun 
    halt 200, found_player.to_json(include: :team)

   else
    halt 400, found_player.errors.full_messages.to_sentence.to_json
   end      
  end
```
<div style="page-break-after: always;"></div>

## Delete
 this allowed us to remove our players from the league.  Gone from the database. 
```
delete "/players/:id" do
    ply = Player.find(params[:id])
    ply.destroy
    ply.to_json
```

<div style="page-break-after: always;"></div>

# Conclusion

<div style="page-break-after: always;"></div>

This project had a huge learning curve for me and my partner.  A lot of time was spent researching and debugging problems.  Organization for this project got away from us at times, but in the end we achieved the minimum project and still have a lot of work to do with this project.  This blog post will be updated and have more to come on a finished project as we refactor code and add features.

## TLDR: Sinatra kicked our but, ruby is a lot of information and is a powerful backend, we are not finished yet but we will be eventually.