I am trying to retrieve the series, seasons and episodes from the movie database, however I am pretty new to Ruby on rails and I feel like what I am doing could be improved a lot.
I use an ActiveJob
to retrieve all the data, and call the job in the after_initialize
initializer.
Here is the code for the job:
# app/jobs/get_series_job.rb
# frozen_string_literal: true
require "httparty"
class GetSeriesJob < ApplicationJob
queue_as :default
API_URL = "https://api.themoviedb.org/3/".freeze
LANGS = { "fr" => "&language=fr-FR", "en" => "&language=en-EN" }.freeze
def perform
save_genres_series_seasons_episodes
end
private
def get_genres
genres_array = []
LANGS.each do |lang|
json = HTTParty.get(
API_URL +
"genre/tv/list?api_key=" +
ENV["API_KEY"] +
lang[1]
)
genres = JSON.parse(json.body)["genres"]
genres.each do |genre|
genre["lang"] = lang[0]
end
genres_array += genres
end
genres_array
end
def save_genre(genre)
return unless !Genre.
where(external_id: genre["id"], lang: genre["lang"])
.exists?
Genre
.new(
name: genre["name"],
external_id: genre["id"],
lang: genre["lang"]
).save
end
def get_series
series = []
LANGS.each do |lang|
json = HTTParty.get(
API_URL +
"tv/popular?api_key=" +
ENV["API_KEY"] +
lang[1]
)
tmp = JSON.parse(json.body)["results"]
tmp.each do |t|
if (serie = series.detect { |s| s["id"] == t["id"] })
serie["name_" + lang[0]] = t["name"]
serie["overview_" + lang[0]] = t["overview"]
serie.delete("name")
serie.delete("overview")
else
t["name_" + lang[0]] = t["name"]
t["overview_" + lang[0]] = t["overview"]
end
end
series = tmp if series.count.zero?
end
series
end
def get_serie(id)
serie_info = HTTParty.get(
API_URL +
"tv/" +
id.to_s +
"?api_key=" +
ENV["API_KEY"]
)
JSON.parse(serie_info.body)
end
def save_serie_genre(serie, genre_ids)
genre_ids.each do |genre_id|
SeriesGenreFr.new(
serie: serie,
genre: Genre.where(external_id: genre_id, lang: "fr").first
).save
SeriesGenreEn.new(
serie: serie,
genre: Genre.where(external_id: genre_id, lang: "en").first
).save
end
end
def save_serie(serie, serie_info)
return unless !Serie.exists?(external_id: serie["id"])
new_serie = Serie.new(
original_name: serie["original_name"],
popularity: serie["popularity"],
origin_country: serie["origin_country"],
vote_count: serie["vote_count"],
first_air_date: serie["first_air_date"],
backdrop_path: serie["backdrop_path"],
original_language: serie["original_language"],
external_id: serie["id"],
vote_average: serie["vote_average"],
overview_en: serie["overview_en"],
overview_fr: serie["overview_fr"],
poster_path: serie["poster_path"],
name_en: serie["name_en"],
name_fr: serie["name_fr"],
episode_run_time: serie_info["episode_run_time"],
number_of_seasons: serie_info["number_of_seasons"]
)
new_serie.save
save_serie_genre(new_serie, serie["genre_ids"])
new_serie.id
end
def get_season(serie_id, season_number)
season = nil
LANGS.each do |lang|
json = HTTParty.get(
API_URL +
"tv/" +
serie_id.to_s +
"/season/" +
season_number.to_s +
"?api_key=" +
ENV["API_KEY"] +
lang[1]
)
tmp = JSON.parse(json.body)
if !tmp["episodes"].nil?
tmp["episodes"].each do |episode|
episode["name_" + lang[0]] = episode["name"]
episode["overview_" + lang[0]] = episode["overview"]
end
end
if season.nil?
season = tmp
season["name_" + lang[0]] = tmp["name"]
season["overview_" + lang[0]] = tmp["overview"]
else
season["name_" + lang[0]] = tmp["name"]
season["overview_" + lang[0]] = tmp["overview"]
if !tmp["episodes"].nil?
tmp["episodes"].each do |e|
if (episode = season["episodes"].detect { |ep| ep["id"] == e["id"] })
episode["name_" + lang[0]] = e["name"]
episode["overview_" + lang[0]] = e["overview"]
end
end
end
end
end
season.delete("name")
season.delete("overview")
season
end
def save_season(season, serie_id)
return unless !Season.exists?(external_id: season["_id"])
new_season = Season.new(
air_date: season["air_date"],
name_en: season["name_en"],
name_fr: season["name_fr"],
episode_count: season["episodes"] ? season["episodes"].count : 0,
overview_en: season["overview_en"],
overview_fr: season["overview_fr"],
external_id: season["_id"],
poster_path: season["poster_path"],
season_number: season["season_number"],
serie_id: serie_id
)
new_season.save
new_season.id
end
def save_genres_series_seasons_episodes
genres = get_genres
genres.each do |genre|
save_genre(genre)
end
episodes = []
episode_columns = [
:air_date,
:name_en,
:name_fr,
:overview_en,
:overview_fr,
:external_id,
:still_path,
:vote_average,
:episode_number,
:season_id,
:vote_count
]
series = get_series
series.each do |serie|
# Get serie
serie_info = get_serie(serie["id"].to_s)
serie_id = save_serie(serie, serie_info)
nb_season = serie_info["number_of_seasons"]
until nb_season.zero?
# Get season
season = get_season(serie["id"], nb_season)
season_id = save_season(season, serie_id)
# Get episode
if season["episodes"]
season["episodes"].each do |episode|
episode = Episode.new(
air_date: episode["air_date"],
name_en: episode["name_en"],
name_fr: episode["name_fr"],
overview_en: episode["overview_en"],
overview_fr: episode["overview_fr"],
external_id: episode["id"],
still_path: episode["still_path"],
vote_average: episode["vote_average"],
vote_count: episode["vote_count"],
episode_number: episode["episode_number"],
season_id: season_id
)
episodes.push episode
end
end
nb_season -= 1
end
end
Episode.import episode_columns, episodes, validate: true
end
end
Here are the migrations:
# db/migrate/20180612124443_create_genres.rb
class CreateGenres < ActiveRecord::Migration[5.2]
def change
create_table :genres do |t|
t.integer :external_id
t.string :name
t.string :lang
t.timestamps
end
end
end
# db/migrate/20180612125317_create_series.rb
class CreateSeries < ActiveRecord::Migration[5.2]
def change
create_table :series do |t|
t.string :original_name
t.string :name_en
t.string :name_fr
t.string :popularity
t.string :origin_country
t.integer :vote_count
t.date :first_air_date
t.string :backdrop_path
t.string :original_language
t.float :vote_average
t.string :overview_en
t.string :overview_fr
t.string :poster_path
t.string :episode_run_time
t.integer :number_of_seasons
t.integer :external_id
t.timestamps
end
end
end
# db/migrate/20180612142042_create_seasons.rb
class CreateSeasons < ActiveRecord::Migration[5.2]
def change
create_table :seasons do |t|
t.date :air_date
t.integer :episode_count
t.string :name_en
t.string :name_fr
t.string :overview_en
t.string :overview_fr
t.integer :season_number
t.string :poster_path
t.references :serie, foreign_key: true
t.string :external_id
t.timestamps
end
end
end
# db/migrate/20180612143220_create_episodes.rb
class CreateEpisodes < ActiveRecord::Migration[5.2]
def change
create_table :episodes do |t|
t.date :air_date
t.string :name_en
t.string :name_fr
t.string :overview_en
t.string :overview_fr
t.string :external_id
t.string :still_path
t.float :vote_average
t.integer :episode_number
t.references :season, foreign_key: true
t.integer :vote_count
t.timestamps
end
end
end
# db/migrate/20180629104316_create_series_genre_frs.rb
class CreateSeriesGenreFrs < ActiveRecord::Migration[5.2]
def change
create_table :series_genre_frs do |t|
t.references :genre, foreign_key: true
t.references :serie, foreign_key: true
t.timestamps
end
end
end
# db/migrate/20180629104823_create_series_genre_ens.rb
class CreateSeriesGenreEns < ActiveRecord::Migration[5.2]
def change
create_table :series_genre_ens do |t|
t.references :genre, foreign_key: true
t.references :serie, foreign_key: true
t.timestamps
end
end
end
Here is the code for the initializer:
# config/initializers/after_initialize.rb
# frozen_string_literal: true
GetSeriesJob.perform_later
The initializer is only for development use. In production I would use a crontab to run the job every day (with the whenever gem).