DEV Community

andrewjpwalters
andrewjpwalters

Posted on

Phase 3 Project Wrap-up

It’s time! I’m now finishing up my phase 3 final project at Flatiron School. In this phase we covered a lot of things: Ruby basics, the fundamentals of the backend of an app, Active Record and Sinatra.
 
Ruby is a pleasure to work with. I wonder if it would’ve been such a breeze to get into if I didn’t have any familiarity with JavaScript, but as it stands, its emphasis on clean readability is very welcome. I appreciate Yukihiro Matsumoto’s desire to make programmers happy and, although I am a newcomer to this field and especially to this language, I think I can see why it’s such a popular language.
 
Working with Active Record was also refreshing. As always, I appreciate learning how to do something the hard way before learning the shortcut—or in this case, the modern, efficient way. The same goes for Sinatra. Sometimes I feel like I’m cheating, knowing how many steps are automated by these wonderful tools.
 
The guidelines for this project were relatively straightforward, building on the things we’d learned in the past phases—particularly React and assembling frontend applications. I was required to: Use Active Record to start a database with at least two models with a one-to-many relationship, use Sinatra to set up API routes for both models (with create and read actions for both and one with full CRUD), and, as I stated, create a front end with React to interact with the API and utilize those CRUD capabilities.
 
I was at a bit of a loss of what to create that would hit all these guidelines and still be an app I could see using, and finally I settled on my reliable love of film to provide an answer: A movie watchlist, where the user can add films they would like to watch and filter them by genre. Genre and movie would be my two models, with MANY movies belonging to ONE genre. The movies model ended up being the one receiving full CRUD—the ability to create new movies, as well as list all the movies saved, edit any comments left on the individual movies as well as delete them from the database.
 
First, I created a very simple framework of a React application, setting up the very basic components I would need. But I could only go so far without any information to feed through an API. So, I had to create one.
 
To set up these models I called on the ever-handy Rake:

 

bundle exec rake db:create_migration NAME=create_movies
bundle exec rake db:create_migration NAME=create_genre
Enter fullscreen mode Exit fullscreen mode

 
These lines called on Active Record to create two migrations, one for a movies table and one for a genres table. From there I defined the rows for movies:

 

class CreateMovies < ActiveRecord::Migration[6.1]
  def change
    create_table :movies do |t|
      t.string :name
      t.integer :genre_id
      t.integer :year
      t.string :comment
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

 
And for genres:

 

class CreateGenres < ActiveRecord::Migration[6.1]
  def change
    create_table :genres do |t|
      t.string :name
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

 
From there I had to write my models and establish their association. Once again, Active Record made it shockingly easy, utilizing the has_many and belongs_to macros :

 

class Movie < ActiveRecord::Base
    belongs_to :genre
end
Enter fullscreen mode Exit fullscreen mode

 
And for genres:

 

class Genre < ActiveRecord::Base
    has_many :movies
end
Enter fullscreen mode Exit fullscreen mode

 
And that was it for Active Record! I just had to create my migration:

 

bundle exec rake db:migrate
Enter fullscreen mode Exit fullscreen mode

 
And my schema was created and ready to be populated with date! After installing Faker, I filled the seed.rb with some randomized movie data and provide a strong base of genres to get started with.
 
Next Sinatra came into play, and this is where I started to hit some snags. Here I had to write my pathways and assign my models some CRUD. Because my two models were associated, I knew I needed to include a special keyword “includes” in my pathway definitions. That was simple enough when creating and reading for my models:

 

class ApplicationController < Sinatra::Base
  set :default_content_type, 'application/json'
  
  get "/movies" do
    movies = Movie.all.order(:name)
    movies.to_json(include: :genre)
  end
 
  get "/genres" do
    genres = Genre.all.order(:name)
    genres.to_json(include: :movies)
  end
 
  post "/movies" do
    movie = Movie.create(name: params[:name], genre_id: params[:genre_id], year: params[:year], comment: params[:comment])
    movie.to_json(include: :genre)
  end
 
  post "/genres" do
    genre = Genre.create(name: params[:name])
    genre.to_json(include: :movies)
  end
 
end
Enter fullscreen mode Exit fullscreen mode

 
But for some reason, when it came to writing my patch and delete methods, I kept getting strange errors and my React application would break. The strangest thing is I was getting no errors from my API. Only from React. When I would refresh the page, the changes I’d made—whether a deleted movie or patched comment—would be rendered just fine. It was only during the act of rendering those changes in my front end application would the app break. My first clue was that trying to access the genre name through each movie, rather than the genre_id property, and the error would tell me it didn’t recognize “genre” and would declare it undefined. Although it didn’t occur to me at first, I once again had to include the associated model in my pathway definition. For some reason, I seemed to think that information was already packaged with the instance once it was created. But once I added that all important “include” keyword, the errors went away:

 

  patch "/movies/:id" do
    movie = Movie.find(params[:id])
    movie.update(comment: params[:comment])
    movie.to_json(include: :genre)
  end
 
  delete "/movies/:id" do
    movie = Movie.find(params[:id])
    movie.destroy
    movie.to_json(inlude: :genre)
  end
Enter fullscreen mode Exit fullscreen mode

 
It took me longer than I would care to admit to solve this in-retrospect simple problem, but once I got it up and working, the struggle and headache was worth it.

Top comments (0)