Introduction
Requirements
- Use the Ruby on Rails framework.
- Design models with at least one
has_many
, at least onebelongs_to
, and at least twohas_many :through
relationships. Also, include a 1many-to-many1 relationship withhas_many :through
associations. The join table must include a user-submittable attribute. - The models must include reasonable validations for the simple attributes which defend against invalid data.
- You must include at least one class level ActiveRecord scope method, which is chainable.
- Provide standard user authentication, including signup, login, logout, and passwords.
- Provide an authentication system which allows login from some other service. Facebook, Twitter, Foursquare, Github, etc...
- You must include and make use of a nested resource with the appropriate RESTful URLs.
TLTR: Feel free to get the source code.
App Design
The overall design and idea of the App was to allow the user to see a list of current movies, read details about the movie and save a secure WatchList that the user could add personal comments. The overall structure includes three models: User, Movies, and WatchList. The Movie model is where the logic for retrieving and storing data resides, and the WatchList model concerns the management of the users watch lists.
Security
To handle the security of the user model, this app utilizes Devise. The default Devise validation has been enhanced:
# Additional validations
EMAIL_REGEX = /\A[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}\z/i.freeze
validates :email, presence: true, format: EMAIL_REGEX
validates :password, length: { in: 6..20 }
The API keys for MovieDb have been secured via DOTENV locally and of course the .env
file is excluded from the repository via .gitignore.
Fetching API
For accessing the data I used the MovieDB API, which is a well documented API and was a joy to work with. These is a level of complexity of the JSON data from the API, and required a multiple tiered approach.
Popular Movies Data
The beginning of the app starts with downloading a series of twenty movies from the API, using the Rest Client gem. Also, to meet the requires of this project for Flatiron, I decided to write the specific data to a databse table in SQlite3. The method accesses the JSON data from the API, checks the DB for each movie, and then writes the required movie data to the DB table:
def movie_popular(page)
data = JSON.parse(RestClient.get("https://api.themoviedb.org/3/movie/popular?api_key=#{ENV['MOVIE_API']}&page=#{page.to_s}"))
data['results'].each do |movie|
existing_movies = Movie.find_by(movie_id: movie['id'])
next if existing_movies
new_movie = Movie.new do |m|
m.movie_id = movie['id']
m.title = movie['title']
m.release_date = movie['release_date']
m.poster_path = movie['poster_path']
m.backdrop_path = movie['backdrop_path']
m.overview = movie['overview']
m.average_vote = movie['vote_average']
end
new_movie.save
end
end
Since, the first access to the API reads and writes twenty movies, I change to include and seed the DB at the project start, vie seed.rb
like so:
# Seed 20 movies
movie_seed = JSON.parse(RestClient.get("https://api.themoviedb.org/3/movie/popular?api_key=#{ENV['MOVIE_API']}&page=1"))
movie_seed['results'].each do |movie|
Movie.create(
movie_id: movie['id'],
title: movie['title'],
release_date: movie['release_date'],
poster_path: movie['poster_path'],
backdrop_path: movie['backdrop_path'],
overview: movie['overview'],
average_vote: movie['vote_average']
)
end
Movie Details
The first pass at the API does not yield all the data I needed for the Movie Detail page. The movie detail call to the API is structured differently, with some data the same, but some structured differently. So, in this case, I called the API based on a movie_id
, write specific data to an existing table entry, and used the DB table to populate the detail page:
def movie_detail(loc_movie)
detail_data = JSON.parse(RestClient.get("https://api.themoviedb.org/3/movie/#{loc_movie}?api_key=#{ENV['MOVIE_API']}"))
edit_movie = Movie.find_by(movie_id: loc_movie)
edit_movie.budget = detail_data['budget']
edit_movie.tagline = detail_data['tagline']
edit_movie.runtime = detail_data['runtime']
edit_movie.save
end
Future Plans
Again because of the API complexity to provide the specific info I need, I am planning to migrate to Postgres. For instance, I need to add Genre tags to the movies. The Genre names are available in the Movie Detail but only as a hash, which Postgres supports.
The next article in this series will explore what I learned Styling this project (i.e. CSS/SCSS/ TailwindCSS).
Top comments (0)