From 49f7ab514e2ca5d9c0f8ce55362b313d9f38b751 Mon Sep 17 00:00:00 2001 From: Gilbert Date: Mon, 8 Dec 2014 08:49:01 -0600 Subject: [PATCH 1/8] Starter code for songify exercise --- Gemfile | 3 ++ Gemfile.lock | 13 ++++++ Rakefile | 50 +++++++++++++++++++++ lib/songify.rb | 48 ++++++++++++++++++++ lib/songify/album_repo.rb | 33 ++++++++++++++ lib/songify/genre_repo.rb | 33 ++++++++++++++ lib/songify/song_repo.rb | 32 +++++++++++++ server.rb | 42 ++++++++++++++++++ spec/.gitkeep | 0 spec/repos/album_repo_spec.rb | 79 ++++++++++++++++++++++++++++++++ spec/repos/genre_repo_spec.rb | 66 +++++++++++++++++++++++++++ spec/repos/song_repo_spec.rb | 84 +++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 13 ++++++ views/albums/index.erb | 15 +++++++ views/genres/index.erb | 15 +++++++ views/index.erb | 8 ++++ 16 files changed, 534 insertions(+) create mode 100644 Rakefile create mode 100644 lib/songify.rb create mode 100644 lib/songify/album_repo.rb create mode 100644 lib/songify/genre_repo.rb create mode 100644 lib/songify/song_repo.rb create mode 100644 server.rb delete mode 100644 spec/.gitkeep create mode 100644 spec/repos/album_repo_spec.rb create mode 100644 spec/repos/genre_repo_spec.rb create mode 100644 spec/repos/song_repo_spec.rb create mode 100644 spec/spec_helper.rb create mode 100644 views/albums/index.erb create mode 100644 views/genres/index.erb create mode 100644 views/index.erb diff --git a/Gemfile b/Gemfile index 1f478929..cc9b3f83 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,6 @@ ruby '2.0.0' gem 'rspec', '~> 2.14.1' gem 'pry-byebug' +gem 'pg' +gem 'sinatra' +gem 'rake' diff --git a/Gemfile.lock b/Gemfile.lock index a885a8c7..8da63939 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,6 +10,7 @@ GEM debugger-linecache (1.2.0) diff-lcs (1.2.5) method_source (0.8.2) + pg (0.17.1) pry (0.10.1) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -17,6 +18,10 @@ GEM pry-byebug (2.0.0) byebug (~> 3.4) pry (~> 0.10) + rack (1.5.2) + rack-protection (1.5.3) + rack + rake (10.3.2) rspec (2.14.1) rspec-core (~> 2.14.0) rspec-expectations (~> 2.14.0) @@ -25,11 +30,19 @@ GEM rspec-expectations (2.14.5) diff-lcs (>= 1.1.3, < 2.0) rspec-mocks (2.14.5) + sinatra (1.4.5) + rack (~> 1.4) + rack-protection (~> 1.4) + tilt (~> 1.3, >= 1.3.4) slop (3.6.0) + tilt (1.4.1) PLATFORMS ruby DEPENDENCIES + pg pry-byebug + rake rspec (~> 2.14.1) + sinatra diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..5f19a6ca --- /dev/null +++ b/Rakefile @@ -0,0 +1,50 @@ + +task :environment do + require './lib/songify.rb' +end + +task :console => :environment do + require 'irb' + ARGV.clear + IRB.start +end + + +namespace :db do + + task :create do + `createdb songify_test` + `createdb songify_dev` + puts "Created." + end + + task :drop do + `dropdb songify_test` + `dropdb songify_dev` + puts "Dropped." + end + + task :create_tables => :environment do + db1 = Songify.create_db_connection('songify_test') + db2 = Songify.create_db_connection('songify_dev') + Songify.create_tables(db1) + Songify.create_tables(db2) + puts "Created tables." + end + + task :drop_tables => :environment do + db1 = Songify.create_db_connection('songify_test') + db2 = Songify.create_db_connection('songify_dev') + Songify.drop_tables(db1) + Songify.drop_tables(db2) + puts "Dropped tables." + end + + task :clear => :environment do + # The test db clears all the time, so there's no point in doing it here. + db = Songify.create_db_connection('songify_dev') + Songify.drop_tables(db) + puts "Cleared tables." + end + +end diff --git a/lib/songify.rb b/lib/songify.rb new file mode 100644 index 00000000..90548c82 --- /dev/null +++ b/lib/songify.rb @@ -0,0 +1,48 @@ +require 'pg' + +module Songify + def self.create_db_connection(dbname) + PG.connect(host: 'localhost', dbname: dbname) + end + + def self.clear_db(db) + db.exec <<-SQL + DELETE FROM albums; + DELETE FROM songs; + DELETE FROM genres; + /* TODO: Clear rest of the tables (books, etc.) */ + SQL + end + + def self.create_tables(db) + db.exec <<-SQL + CREATE TABLE albums( + id SERIAL PRIMARY KEY, + title VARCHAR + ); + CREATE TABLE songs( + id SERIAL PRIMARY KEY, + album_id integer REFERENCES genres (id), + title VARCHAR + ); + CREATE TABLE genres( + id SERIAL PRIMARY KEY, + name VARCHAR + ); + /* TODO: Create song_genres table */ + SQL + end + + def self.drop_tables(db) + db.exec <<-SQL + DROP TABLE albums; + DROP TABLE songs; + DROP TABLE genres; + /* TODO: Drop song_genres table */ + SQL + end +end + +require_relative 'songify/album_repo' +require_relative 'songify/genre_repo' +require_relative 'songify/song_repo' diff --git a/lib/songify/album_repo.rb b/lib/songify/album_repo.rb new file mode 100644 index 00000000..54b55451 --- /dev/null +++ b/lib/songify/album_repo.rb @@ -0,0 +1,33 @@ +module Songify + class AlbumRepo + + def self.all(db) + # Other code should not have to deal with the PG:Result. + # Therefore, convert the results into a plain array. + db.exec("SELECT * FROM albums").to_a + end + + def self.find(db, album_id) + db.exec("SELECT * FROM albums WHERE id=$1", [album_id]).first + end + + def self.save(db, album_data) + if album_data['id'] + result = db.exec("UPDATE albums SET title = $2 WHERE id = $1", [album_data['id'], album_data['title']]) + self.find(db, album_data['id']) + else + raise "title is required." if album_data['title'].nil? || album_data['title'] == '' + result = db.exec("INSERT INTO albums (title) VALUES ($1) RETURNING id", [album_data['title']]) + album_data['id'] = result.entries.first['id'] + album_data + end + end + + def self.destroy(db, album_id) + # TODO: Delete SQL statement + # ALSO DELETE SONGS + # ALSO DELETE JOIN TABLE ENTRIES BETWEEN THIS ALBUM AND ITS GENRES + end + + end +end diff --git a/lib/songify/genre_repo.rb b/lib/songify/genre_repo.rb new file mode 100644 index 00000000..558261b5 --- /dev/null +++ b/lib/songify/genre_repo.rb @@ -0,0 +1,33 @@ +module Songify + class GenreRepo + + def self.all(db) + # Other code should not have to deal with the PG:Result. + # Therefore, convert the results into a plain array. + db.exec("SELECT * FROM genres").to_a + end + + def self.find(db, genre_id) + db.exec("SELECT * FROM genres WHERE id=$1", [genre_id]).first + end + + def self.save(db, genre_data) + if genre_data['id'] + result = db.exec("UPDATE genres SET name = $2 WHERE id = $1", [genre_data['id'], genre_data['name']]) + self.find(db, genre_data['id']) + else + raise "name is required." if genre_data['name'].nil? || genre_data['name'] == '' + + result = db.exec("INSERT INTO genres (name) VALUES ($1) RETURNING id", [genre_data['name']]) + genre_data['id'] = result.entries.first['id'] + genre_data + end + end + + def self.destroy(db, genre_id) + # TODO: Delete SQL statement + # ALSO DELETE JOIN TABLE ENTRIES BETWEEN THIS GENRE AND ITS ALBUMS + end + + end +end diff --git a/lib/songify/song_repo.rb b/lib/songify/song_repo.rb new file mode 100644 index 00000000..a9fc10c0 --- /dev/null +++ b/lib/songify/song_repo.rb @@ -0,0 +1,32 @@ +module Songify + class SongRepo + + def self.all(db) + # Other code should not have to deal with the PG:Result. + # Therefore, convert the results into a plain array. + db.exec("SELECT * FROM songs").to_a + end + + def self.find(db, song_id) + db.exec("SELECT * FROM songs WHERE id=$1", [song_id]).first + end + + def self.save(db, song_data) + if song_data['id'] + result = db.exec("UPDATE songs SET title = $2 WHERE id = $1", [song_data['id'], song_data['title']]) + self.find(db, song_data['id']) + else + raise "title is required." if song_data['title'].nil? || song_data['title'] == '' + + # Ensure album exists + album = AlbumRepo.find(db, song_data['album_id']) + raise "A valid album_id is required." if album.nil? + + result = db.exec("INSERT INTO songs (title) VALUES ($1) RETURNING id", [song_data['title']]) + song_data['id'] = result.entries.first['id'] + song_data + end + end + + end +end diff --git a/server.rb b/server.rb new file mode 100644 index 00000000..361bacc7 --- /dev/null +++ b/server.rb @@ -0,0 +1,42 @@ +require 'sinatra' +require './lib/songify.rb' + +# set :bind, '0.0.0.0' # This is needed for Vagrant + +get '/' do + erb :index +end + +get '/albums' do + db = Songify.create_db_connection('songify_dev') + @albums = Songify::AlbumRepo.all(db) + erb :"albums/index" +end + +post '/albums' do + db = Songify.create_db_connection('songify_dev') + album = Songify::AlbumRepo.save(db, { + 'title' => params[:title] + }) + redirect to '/albums' +end + + +get '/songs' do + erb :"songs/index" +end + + +get '/genres' do + db = Songify.create_db_connection('songify_dev') + @genres = Songify::GenreRepo.all(db) + erb :"genres/index" +end + +post '/genres' do + db = Songify.create_db_connection('songify_dev') + album = Songify::GenreRepo.save(db, { + 'name' => params[:name] + }) + redirect to '/genres' +end diff --git a/spec/.gitkeep b/spec/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/repos/album_repo_spec.rb b/spec/repos/album_repo_spec.rb new file mode 100644 index 00000000..3f080f05 --- /dev/null +++ b/spec/repos/album_repo_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper' + +describe Songify::AlbumRepo do + + def album_count + repo.all(db).count + end + + let(:repo) { Songify::AlbumRepo } + let(:db) { Songify.create_db_connection('songify_test') } + + before(:each) do + Songify.clear_db(db) + end + + it "gets all albums" do + album = repo.save(db, { 'title' => "Allybum" }) + album = repo.save(db, { 'title' => "Bluesbum" }) + + albums = repo.all(db) + expect(albums).to be_a Array + expect(albums.count).to eq 2 + + titles = albums.map {|u| u['title'] } + expect(titles).to include "Allybum", "Bluesbum" + end + + it "creates albums" do + expect(album_count).to eq 0 + + album = repo.save(db, { 'title' => "Allybum" }) + expect(album['id']).to_not be_nil + expect(album['title']).to eq "Allybum" + + # Check for persistence + expect(album_count).to eq 1 + + album = repo.all(db).first + expect(album['title']).to eq "Allybum" + end + + it "requires a title" do + expect { repo.save(db, {}) }.to raise_error {|e| + expect(e.message).to match /title/ + } + end + + xit "can be assigned genres" do + gid_1 = Songify::GenreRepo.save(db, { 'name' => 'rock' }) + gid_2 = Songify::GenreRepo.save(db, { 'name' => 'avant-garde' }) + gid_3 = Songify::GenreRepo.save(db, { 'name' => 'jazz' }) + + album = repo.save(db, { 'title' => 'Suspicious Activity?', + 'genre_ids' => [gid_1['id'], gid_2['id'], gid_3['id']] }) + album = repo.find(db, album['id']) + expect(album['genres'].count).to eq 3 + + names = album['genres'].map {|g| g['name'] } + expect(names).to include 'rock', 'avant-garde', 'jazz' + end + + it "finds albums" do + album = repo.save(db, { 'title' => "Allybum" }) + retrieved_song = repo.find(db, album['id']) + expect(retrieved_song['title']).to eq "Allybum" + end + + it "updates albums" do + song1 = repo.save(db, { 'title' => "Allybum" }) + song2 = repo.save(db, { 'id' => song1['id'], 'title' => "Alicia" }) + expect(song2['id']).to eq(song1['id']) + expect(song2['title']).to eq "Alicia" + + # Check for persistence + song3 = repo.find(db, song1['id']) + expect(song3['title']).to eq "Alicia" + end + +end diff --git a/spec/repos/genre_repo_spec.rb b/spec/repos/genre_repo_spec.rb new file mode 100644 index 00000000..3e7664bf --- /dev/null +++ b/spec/repos/genre_repo_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe Songify::GenreRepo do + + def genre_count + repo.all(db).count + end + + let(:repo) { Songify::GenreRepo } + let(:db) { Songify.create_db_connection('songify_test') } + + before(:each) do + Songify.clear_db(db) + end + + it "gets all genres" do + genre = repo.save(db, { 'name' => "The Ally" }) + genre = repo.save(db, { 'name' => "Barnway Blues" }) + + genres = repo.all(db) + expect(genres).to be_a Array + expect(genres.count).to eq 2 + + titles = genres.map {|u| u['name'] } + expect(titles).to include "The Ally", "Barnway Blues" + end + + it "creates genres" do + expect(genre_count).to eq 0 + + genre = repo.save(db, { 'name' => "The Ally" }) + expect(genre['id']).to_not be_nil + expect(genre['name']).to eq "The Ally" + + # Check for persistence + expect(genre_count).to eq 1 + + genre = repo.all(db).first + expect(genre['name']).to eq "The Ally" + end + + it "requires a name" do + expect { repo.save(db, {}) }.to raise_error {|e| + expect(e.message).to match /name/ + } + end + + + it "finds genres" do + genre = repo.save(db, { 'name' => "The Ally" }) + retrieved_song = repo.find(db, genre['id']) + expect(retrieved_song['name']).to eq "The Ally" + end + + it "updates genres" do + song1 = repo.save(db, { 'name' => "The Ally" }) + song2 = repo.save(db, { 'id' => song1['id'], 'name' => "Alicia" }) + expect(song2['id']).to eq(song1['id']) + expect(song2['name']).to eq "Alicia" + + # Check for persistence + song3 = repo.find(db, song1['id']) + expect(song3['name']).to eq "Alicia" + end + +end diff --git a/spec/repos/song_repo_spec.rb b/spec/repos/song_repo_spec.rb new file mode 100644 index 00000000..d9a823e7 --- /dev/null +++ b/spec/repos/song_repo_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper' + +describe Songify::SongRepo do + + def song_count + repo.all(db).count + end + + let(:repo) { Songify::SongRepo } + let(:db) { Songify.create_db_connection('songify_test') } + + before(:each) do + Songify.clear_db(db) + @album_id = Songify::AlbumRepo.save(db, { 'title' => "MegaCorps" })['id'] + end + + it "gets all songs" do + song = repo.save(db, { 'album_id' => @album_id, 'title' => "The Ally" }) + song = repo.save(db, { 'album_id' => @album_id, 'title' => "Barnway Blues" }) + + songs = repo.all(db) + expect(songs).to be_a Array + expect(songs.count).to eq 2 + + titles = songs.map {|u| u['title'] } + expect(titles).to include "The Ally", "Barnway Blues" + end + + it "creates songs" do + expect(song_count).to eq 0 + + song = repo.save(db, { 'album_id' => @album_id, 'title' => "The Ally" }) + expect(song['id']).to_not be_nil + expect(song['title']).to eq "The Ally" + + # Check for persistence + expect(song_count).to eq 1 + + song = repo.all(db).first + expect(song['title']).to eq "The Ally" + end + + it "requires a title" do + expect { repo.save(db, {}) }.to raise_error {|e| + expect(e.message).to match /title/ + } + end + + it "requires an album id" do + expect { + repo.save(db, { 'title' => "The Ally" }) + } + .to raise_error {|e| + expect(e.message).to match /album_id/ + } + end + + it "requires an album id that exists" do + expect { + repo.save(db, { 'album_id' => 999, 'title' => "The Ally" }) + } + .to raise_error {|e| + expect(e.message).to match /album_id/ + } + end + + it "finds songs" do + song = repo.save(db, { 'album_id' => @album_id, 'title' => "The Ally" }) + retrieved_song = repo.find(db, song['id']) + expect(retrieved_song['title']).to eq "The Ally" + end + + it "updates songs" do + song1 = repo.save(db, { 'album_id' => @album_id, 'title' => "The Ally" }) + song2 = repo.save(db, { 'id' => song1['id'], 'title' => "Alicia" }) + expect(song2['id']).to eq(song1['id']) + expect(song2['title']).to eq "Alicia" + + # Check for persistence + song3 = repo.find(db, song1['id']) + expect(song3['title']).to eq "Alicia" + end + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 00000000..b15d3bbc --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,13 @@ +require 'songify' + +RSpec.configure do |config| + config.treat_symbols_as_metadata_keys_with_true_values = true + config.run_all_when_everything_filtered = true + config.filter_run :focus + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = 'random' +end diff --git a/views/albums/index.erb b/views/albums/index.erb new file mode 100644 index 00000000..fa67cd23 --- /dev/null +++ b/views/albums/index.erb @@ -0,0 +1,15 @@ +<- Back to Everything +

All Albums

+ + + +
+

New Album

+ + + +
diff --git a/views/genres/index.erb b/views/genres/index.erb new file mode 100644 index 00000000..e62f9b7d --- /dev/null +++ b/views/genres/index.erb @@ -0,0 +1,15 @@ +<- Back to Everything +

All Genres

+ + + +
+

New Genre

+ + + +
diff --git a/views/index.erb b/views/index.erb new file mode 100644 index 00000000..8f52ed98 --- /dev/null +++ b/views/index.erb @@ -0,0 +1,8 @@ +

The Songify System

+ +

You're gonna be big

+ + From cc059f0406b2dc109a3603e346e87980e2fdbee5 Mon Sep 17 00:00:00 2001 From: Glenn Meyer Date: Mon, 8 Dec 2014 21:20:33 +0000 Subject: [PATCH 2/8] fix typo, add album_id --- lib/songify/song_repo.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/songify/song_repo.rb b/lib/songify/song_repo.rb index a9fc10c0..9865dc00 100644 --- a/lib/songify/song_repo.rb +++ b/lib/songify/song_repo.rb @@ -22,7 +22,7 @@ def self.save(db, song_data) album = AlbumRepo.find(db, song_data['album_id']) raise "A valid album_id is required." if album.nil? - result = db.exec("INSERT INTO songs (title) VALUES ($1) RETURNING id", [song_data['title']]) + result = db.exec("INSERT INTO songs (title, album_id) VALUES ($1, $2) RETURNING id", [song_data['title'], song_data['album_id']]) song_data['id'] = result.entries.first['id'] song_data end From bc94a259bcbfcf7f53f7cc1025c6c3fba03280eb Mon Sep 17 00:00:00 2001 From: Glenn Meyer Date: Tue, 9 Dec 2014 04:40:19 +0000 Subject: [PATCH 3/8] finish exercise, three extensions --- lib/songify.rb | 19 +++++++++++++------ lib/songify/album_repo.rb | 17 ++++++++++++++++- lib/songify/genre_repo.rb | 7 +++++++ lib/songify/song_repo.rb | 4 ++++ server.rb | 29 ++++++++++++++++++++++++++--- spec/repos/album_repo_spec.rb | 2 +- views/albums/album.erb | 13 +++++++++++++ views/albums/index.erb | 2 +- views/genres/genre.erb | 8 ++++++++ views/genres/index.erb | 2 +- views/index.erb | 1 + views/songs/index.erb | 21 +++++++++++++++++++++ 12 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 views/albums/album.erb create mode 100644 views/genres/genre.erb create mode 100644 views/songs/index.erb diff --git a/lib/songify.rb b/lib/songify.rb index 90548c82..2fc0c855 100644 --- a/lib/songify.rb +++ b/lib/songify.rb @@ -7,8 +7,9 @@ def self.create_db_connection(dbname) def self.clear_db(db) db.exec <<-SQL - DELETE FROM albums; + DELETE FROM album_genres; DELETE FROM songs; + DELETE FROM albums; DELETE FROM genres; /* TODO: Clear rest of the tables (books, etc.) */ SQL @@ -16,27 +17,33 @@ def self.clear_db(db) def self.create_tables(db) db.exec <<-SQL - CREATE TABLE albums( + CREATE TABLE IF NOT EXISTS albums( id SERIAL PRIMARY KEY, title VARCHAR ); - CREATE TABLE songs( + CREATE TABLE IF NOT EXISTS songs( id SERIAL PRIMARY KEY, - album_id integer REFERENCES genres (id), + album_id integer REFERENCES albums (id), title VARCHAR ); - CREATE TABLE genres( + CREATE TABLE IF NOT EXISTS genres( id SERIAL PRIMARY KEY, name VARCHAR ); /* TODO: Create song_genres table */ + CREATE TABLE IF NOT EXISTS album_genres( + id SERIAL PRIMARY KEY, + album_id integer REFERENCES albums (id), + genre_id integer REFERENCES genres (id) + ); SQL end def self.drop_tables(db) db.exec <<-SQL - DROP TABLE albums; + DROP TABLE album_genres; DROP TABLE songs; + DROP TABLE albums; DROP TABLE genres; /* TODO: Drop song_genres table */ SQL diff --git a/lib/songify/album_repo.rb b/lib/songify/album_repo.rb index 54b55451..9548a93c 100644 --- a/lib/songify/album_repo.rb +++ b/lib/songify/album_repo.rb @@ -8,13 +8,28 @@ def self.all(db) end def self.find(db, album_id) - db.exec("SELECT * FROM albums WHERE id=$1", [album_id]).first + # if album_id.count > 1 + # db.exec("SELECT * FROM album_genres WHERE album_id = $1", [album_id]).first + # else + result = db.exec("SELECT * FROM albums WHERE id = $1", [album_id]).first + genres = db.exec("SELECT * FROM album_genres WHERE album_id = $1", [album_id]).first + result + # end end def self.save(db, album_data) if album_data['id'] result = db.exec("UPDATE albums SET title = $2 WHERE id = $1", [album_data['id'], album_data['title']]) self.find(db, album_data['id']) + elsif album_data['genre_ids'] + album_id = db.exec("INSERT INTO albums (title) VALUES ($1) RETURNING id", [album_data['title']]).first + album_data['genre_ids'].each do |genre| + puts album_id['id'] + puts genre + result = db.exec("INSERT INTO album_genres (album_id, genre_id) VALUES ($1, $2)", [album_id['id'], genre]) + end + puts result.first + album = {'id' => album_id, 'genres' => album_data['genre_ids']} else raise "title is required." if album_data['title'].nil? || album_data['title'] == '' result = db.exec("INSERT INTO albums (title) VALUES ($1) RETURNING id", [album_data['title']]) diff --git a/lib/songify/genre_repo.rb b/lib/songify/genre_repo.rb index 558261b5..af64b51f 100644 --- a/lib/songify/genre_repo.rb +++ b/lib/songify/genre_repo.rb @@ -1,5 +1,8 @@ module Songify class GenreRepo + def self.albums(db, genre_id) + db.exec("SELECT g.name AS genre, a.title AS title, a.id AS album_id FROM genres g JOIN album_genres j ON g.id = j.genre_id JOIN albums a ON a.id = j.album_id WHERE g.id = $1", [genre_id]) + end def self.all(db) # Other code should not have to deal with the PG:Result. @@ -11,6 +14,10 @@ def self.find(db, genre_id) db.exec("SELECT * FROM genres WHERE id=$1", [genre_id]).first end + def self.genres_by_album(db, album_id) + db.exec("SELECT g.name, g.id FROM album_genres a JOIN genres g ON g.id = a.genre_id WHERE a.album_id = $1", [album_id]).to_a + end + def self.save(db, genre_data) if genre_data['id'] result = db.exec("UPDATE genres SET name = $2 WHERE id = $1", [genre_data['id'], genre_data['name']]) diff --git a/lib/songify/song_repo.rb b/lib/songify/song_repo.rb index 9865dc00..c969aa80 100644 --- a/lib/songify/song_repo.rb +++ b/lib/songify/song_repo.rb @@ -11,6 +11,10 @@ def self.find(db, song_id) db.exec("SELECT * FROM songs WHERE id=$1", [song_id]).first end + def self.list(db, album_id) + db.exec("SELECT a.title AS title, s.title AS name FROM songs s JOIN albums a ON a.id = s.album_id WHERE album_id = $1", [album_id]).to_a + end + def self.save(db, song_data) if song_data['id'] result = db.exec("UPDATE songs SET title = $2 WHERE id = $1", [song_data['id'], song_data['title']]) diff --git a/server.rb b/server.rb index 361bacc7..2d1c74c9 100644 --- a/server.rb +++ b/server.rb @@ -1,15 +1,15 @@ require 'sinatra' require './lib/songify.rb' -# set :bind, '0.0.0.0' # This is needed for Vagrant +set :bind, '0.0.0.0' # This is needed for Vagrant get '/' do erb :index end get '/albums' do - db = Songify.create_db_connection('songify_dev') - @albums = Songify::AlbumRepo.all(db) + @db = Songify.create_db_connection('songify_dev') + @albums = Songify::AlbumRepo.all(@db) erb :"albums/index" end @@ -21,11 +21,28 @@ redirect to '/albums' end +get'/albums/:id' do + db = Songify.create_db_connection('songify_dev') + @songs = Songify::SongRepo.list(db, params[:id]) + @genres = Songify::GenreRepo.genres_by_album(db, params[:id]) + erb :"albums/album" +end get '/songs' do + db = Songify.create_db_connection('songify_dev') + @songs = Songify::SongRepo.all(db) + @albums = Songify::AlbumRepo.all(db) erb :"songs/index" end +post '/songs' do + db = Songify.create_db_connection('songify_dev') + song = Songify::SongRepo.save(db, { + 'title' => params[:title], + 'album_id' => params[:album_id] + }) + redirect to '/songs' +end get '/genres' do db = Songify.create_db_connection('songify_dev') @@ -40,3 +57,9 @@ }) redirect to '/genres' end + +get '/genres/:id' do + db = Songify.create_db_connection('songify_dev') + @genres = Songify::GenreRepo.albums(db, params[:id]) + erb :"genres/genre" +end diff --git a/spec/repos/album_repo_spec.rb b/spec/repos/album_repo_spec.rb index 3f080f05..931ebde1 100644 --- a/spec/repos/album_repo_spec.rb +++ b/spec/repos/album_repo_spec.rb @@ -45,7 +45,7 @@ def album_count } end - xit "can be assigned genres" do + it "can be assigned genres" do gid_1 = Songify::GenreRepo.save(db, { 'name' => 'rock' }) gid_2 = Songify::GenreRepo.save(db, { 'name' => 'avant-garde' }) gid_3 = Songify::GenreRepo.save(db, { 'name' => 'jazz' }) diff --git a/views/albums/album.erb b/views/albums/album.erb new file mode 100644 index 00000000..3b6f3bab --- /dev/null +++ b/views/albums/album.erb @@ -0,0 +1,13 @@ +<- Back to Everything +

<%= @songs.first['title'] %> - All Songs

+

+<% @genres.each do |genre| %> + <%= genre['name'] %> | +<% end %> +

+ +
    + <% @songs.each do |song| %> +
  • <%= song['name'] %>
  • + <% end %> +
\ No newline at end of file diff --git a/views/albums/index.erb b/views/albums/index.erb index fa67cd23..62946abd 100644 --- a/views/albums/index.erb +++ b/views/albums/index.erb @@ -3,7 +3,7 @@
    <% @albums.each do |album| %> -
  • <%= album['title'] %>
  • +
  • <%= album['title'] %> - <%= @db.exec("SELECT * FROM songs where album_id = #{album['id']}").to_a.count %> songs
  • <% end %>
diff --git a/views/genres/genre.erb b/views/genres/genre.erb new file mode 100644 index 00000000..7b9272a2 --- /dev/null +++ b/views/genres/genre.erb @@ -0,0 +1,8 @@ +<- Back to Everything +

<%= @genres.first['genre'] %> - All Albums

+ + \ No newline at end of file diff --git a/views/genres/index.erb b/views/genres/index.erb index e62f9b7d..bc8c6edf 100644 --- a/views/genres/index.erb +++ b/views/genres/index.erb @@ -3,7 +3,7 @@ diff --git a/views/index.erb b/views/index.erb index 8f52ed98..10abf7f6 100644 --- a/views/index.erb +++ b/views/index.erb @@ -5,4 +5,5 @@ diff --git a/views/songs/index.erb b/views/songs/index.erb new file mode 100644 index 00000000..a4e60abf --- /dev/null +++ b/views/songs/index.erb @@ -0,0 +1,21 @@ +<- Back to Everything +

All Songs

+ +
    + <% @songs.each do |song| %> +
  • <%= song['title'] %>
  • + <% end %> +
+ +
+

New Song

+ + + + + +
From 17e15a0dca857c26243b1f075cc466b84de48c3a Mon Sep 17 00:00:00 2001 From: Glenn Meyer Date: Tue, 9 Dec 2014 18:23:18 +0000 Subject: [PATCH 4/8] all tests pass --- lib/songify/album_repo.rb | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/songify/album_repo.rb b/lib/songify/album_repo.rb index 9548a93c..3a0f4893 100644 --- a/lib/songify/album_repo.rb +++ b/lib/songify/album_repo.rb @@ -1,3 +1,5 @@ +require 'pry-byebug' + module Songify class AlbumRepo @@ -8,13 +10,16 @@ def self.all(db) end def self.find(db, album_id) - # if album_id.count > 1 - # db.exec("SELECT * FROM album_genres WHERE album_id = $1", [album_id]).first - # else - result = db.exec("SELECT * FROM albums WHERE id = $1", [album_id]).first - genres = db.exec("SELECT * FROM album_genres WHERE album_id = $1", [album_id]).first - result - # end + genres = [] + result = db.exec("SELECT * FROM albums WHERE id = $1", [album_id]).first + if result + album_genres = db.exec("SELECT * FROM album_genres a JOIN genres g ON g.id = a.genre_id WHERE a.album_id = $1", [album_id]).to_a + album_genres.each do |line| + genres << {'id' => line['genre_id'], 'name' => line['name']} + end + result['genres'] = genres + end + result end def self.save(db, album_data) @@ -23,13 +28,11 @@ def self.save(db, album_data) self.find(db, album_data['id']) elsif album_data['genre_ids'] album_id = db.exec("INSERT INTO albums (title) VALUES ($1) RETURNING id", [album_data['title']]).first + album_data['id'] = album_id['id'] album_data['genre_ids'].each do |genre| - puts album_id['id'] - puts genre - result = db.exec("INSERT INTO album_genres (album_id, genre_id) VALUES ($1, $2)", [album_id['id'], genre]) + db.exec("INSERT INTO album_genres (album_id, genre_id) VALUES ($1, $2)", [album_id['id'], genre]) end - puts result.first - album = {'id' => album_id, 'genres' => album_data['genre_ids']} + album_id else raise "title is required." if album_data['title'].nil? || album_data['title'] == '' result = db.exec("INSERT INTO albums (title) VALUES ($1) RETURNING id", [album_data['title']]) From c3673c15faaf4896c69ae6e97b44d027d2f4b2bb Mon Sep 17 00:00:00 2001 From: Glenn Meyer Date: Tue, 9 Dec 2014 13:48:31 -0600 Subject: [PATCH 5/8] tests passed --- server.rb | 1 + views/albums/index.erb | 5 +++++ views/songs/index.erb | 1 + 3 files changed, 7 insertions(+) diff --git a/server.rb b/server.rb index 2d1c74c9..0fc7cfed 100644 --- a/server.rb +++ b/server.rb @@ -10,6 +10,7 @@ get '/albums' do @db = Songify.create_db_connection('songify_dev') @albums = Songify::AlbumRepo.all(@db) + @genres = Songify::GenreRepo.all(@db) erb :"albums/index" end diff --git a/views/albums/index.erb b/views/albums/index.erb index 62946abd..cace13ce 100644 --- a/views/albums/index.erb +++ b/views/albums/index.erb @@ -11,5 +11,10 @@

New Album

+ diff --git a/views/songs/index.erb b/views/songs/index.erb index a4e60abf..ca3c1aeb 100644 --- a/views/songs/index.erb +++ b/views/songs/index.erb @@ -17,5 +17,6 @@ <% end %> + add genre From d6d4c38700e6991392cc2c0f5aa648d1dd7fd578 Mon Sep 17 00:00:00 2001 From: Glenn Meyer Date: Tue, 9 Dec 2014 14:49:48 -0600 Subject: [PATCH 6/8] finish part 3 --- views/albums/index.erb | 32 +++++++++++++++++++++++++++----- views/songs/index.erb | 1 - 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/views/albums/index.erb b/views/albums/index.erb index cace13ce..25dc7567 100644 --- a/views/albums/index.erb +++ b/views/albums/index.erb @@ -11,10 +11,32 @@

New Album

- +
+ + add genre +
+ + + diff --git a/views/songs/index.erb b/views/songs/index.erb index ca3c1aeb..a4e60abf 100644 --- a/views/songs/index.erb +++ b/views/songs/index.erb @@ -17,6 +17,5 @@ <% end %> - add genre From 2f9c492421a2cf8fa9e0d7c8b3a980ce9c201085 Mon Sep 17 00:00:00 2001 From: Glenn Meyer Date: Tue, 9 Dec 2014 20:15:50 -0600 Subject: [PATCH 7/8] finish exercise 2 extensions --- lib/songify/album_repo.rb | 8 +++----- lib/songify/genre_repo.rb | 4 +++- lib/songify/song_repo.rb | 2 +- server.rb | 22 +++++++++++++++++++--- views/albums/album.erb | 27 +++++++++++++++++++++++---- views/genres/genre.erb | 30 +++++++++++++++++++++++++----- 6 files changed, 74 insertions(+), 19 deletions(-) diff --git a/lib/songify/album_repo.rb b/lib/songify/album_repo.rb index 3a0f4893..87fa44c7 100644 --- a/lib/songify/album_repo.rb +++ b/lib/songify/album_repo.rb @@ -4,8 +4,6 @@ module Songify class AlbumRepo def self.all(db) - # Other code should not have to deal with the PG:Result. - # Therefore, convert the results into a plain array. db.exec("SELECT * FROM albums").to_a end @@ -42,9 +40,9 @@ def self.save(db, album_data) end def self.destroy(db, album_id) - # TODO: Delete SQL statement - # ALSO DELETE SONGS - # ALSO DELETE JOIN TABLE ENTRIES BETWEEN THIS ALBUM AND ITS GENRES + db.exec("DELETE FROM album_genres WHERE album_id = $1", [album_id]) + db.exec("DELETE FROM songs WHERE album_id = $1", [album_id]) + db.exec("DELETE FROM albums WHERE id = $1", [album_id]) end end diff --git a/lib/songify/genre_repo.rb b/lib/songify/genre_repo.rb index af64b51f..a6ea3781 100644 --- a/lib/songify/genre_repo.rb +++ b/lib/songify/genre_repo.rb @@ -1,7 +1,7 @@ module Songify class GenreRepo def self.albums(db, genre_id) - db.exec("SELECT g.name AS genre, a.title AS title, a.id AS album_id FROM genres g JOIN album_genres j ON g.id = j.genre_id JOIN albums a ON a.id = j.album_id WHERE g.id = $1", [genre_id]) + db.exec("SELECT g.name AS genre, a.title AS title, a.id AS album_id, g.id AS genre_id FROM genres g JOIN album_genres j ON g.id = j.genre_id JOIN albums a ON a.id = j.album_id WHERE g.id = $1", [genre_id]) end def self.all(db) @@ -34,6 +34,8 @@ def self.save(db, genre_data) def self.destroy(db, genre_id) # TODO: Delete SQL statement # ALSO DELETE JOIN TABLE ENTRIES BETWEEN THIS GENRE AND ITS ALBUMS + db.exec("DELETE FROM album_genres WHERE genre_id = $1", [genre_id]) + db.exec("DELETE FROM genres WHERE id = $1", [genre_id]) end end diff --git a/lib/songify/song_repo.rb b/lib/songify/song_repo.rb index c969aa80..f9c16e50 100644 --- a/lib/songify/song_repo.rb +++ b/lib/songify/song_repo.rb @@ -12,7 +12,7 @@ def self.find(db, song_id) end def self.list(db, album_id) - db.exec("SELECT a.title AS title, s.title AS name FROM songs s JOIN albums a ON a.id = s.album_id WHERE album_id = $1", [album_id]).to_a + db.exec("SELECT a.title AS title, s.title AS name, a.id AS album_id FROM songs s JOIN albums a ON a.id = s.album_id WHERE album_id = $1", [album_id]).to_a end def self.save(db, song_data) diff --git a/server.rb b/server.rb index 0fc7cfed..32eb2cca 100644 --- a/server.rb +++ b/server.rb @@ -1,5 +1,6 @@ require 'sinatra' require './lib/songify.rb' +# Rack::MethodOverride set :bind, '0.0.0.0' # This is needed for Vagrant @@ -17,18 +18,26 @@ post '/albums' do db = Songify.create_db_connection('songify_dev') album = Songify::AlbumRepo.save(db, { - 'title' => params[:title] + 'title' => params[:title], + 'genre_ids' => params[:genre_ids] }) redirect to '/albums' end -get'/albums/:id' do +get '/albums/:id' do db = Songify.create_db_connection('songify_dev') + @albums = Songify::AlbumRepo.find(db, params[:id]) @songs = Songify::SongRepo.list(db, params[:id]) @genres = Songify::GenreRepo.genres_by_album(db, params[:id]) erb :"albums/album" end +delete '/albums/:id' do + db = Songify.create_db_connection('songify_dev') + Songify::AlbumRepo.destroy(db, params[:album_id]) + redirect to '/albums' +end + get '/songs' do db = Songify.create_db_connection('songify_dev') @songs = Songify::SongRepo.all(db) @@ -61,6 +70,13 @@ get '/genres/:id' do db = Songify.create_db_connection('songify_dev') - @genres = Songify::GenreRepo.albums(db, params[:id]) + @genres = Songify::GenreRepo.find(db, params[:id]) + @genres_join = Songify::GenreRepo.albums(db, params[:id]) erb :"genres/genre" end + +delete '/genres/:id' do + db = Songify.create_db_connection('songify_dev') + Songify::GenreRepo.destroy(db, params[:genre_id]) + redirect to '/genres' +end diff --git a/views/albums/album.erb b/views/albums/album.erb index 3b6f3bab..5cc1504e 100644 --- a/views/albums/album.erb +++ b/views/albums/album.erb @@ -1,13 +1,32 @@ <- Back to Everything -

<%= @songs.first['title'] %> - All Songs

+

<%= @albums['title'] %> - All Songs

<% @genres.each do |genre| %> <%= genre['name'] %> | <% end %>

-
    +<% if @songs.first %> <% @songs.each do |song| %> -
  • <%= song['name'] %>
  • +
  • <%= song['name'] %>
  • <% end %> -
\ No newline at end of file +<% else %> +
  • This album does not have any songs.
  • +<% end %> + + +
    + + + +
    + + + \ No newline at end of file diff --git a/views/genres/genre.erb b/views/genres/genre.erb index 7b9272a2..38afb3c4 100644 --- a/views/genres/genre.erb +++ b/views/genres/genre.erb @@ -1,8 +1,28 @@ <- Back to Everything -

    <%= @genres.first['genre'] %> - All Albums

    +

    <%= @genres['name'] %> - All Albums

    \ No newline at end of file + <% if @genres_join.first %> + <% @genres_join.each do |album| %> +
  • <%= album['title'] %>
  • + <% end %> + <% else %> +
  • There are no albums associated with this genre.
  • + <% end %> + + +
    + + + +
    + + + \ No newline at end of file From 52de4c3e5338464560f74a7981799a13aa481bc5 Mon Sep 17 00:00:00 2001 From: Glenn Meyer Date: Tue, 9 Dec 2014 21:38:21 -0600 Subject: [PATCH 8/8] finish exercise, all extensions --- lib/songify/album_repo.rb | 7 +++++++ server.rb | 21 ++++++++++++++++++++- views/albums/album.erb | 5 +++-- views/albums/edit.erb | 39 +++++++++++++++++++++++++++++++++++++++ views/genres/genre.erb | 2 +- 5 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 views/albums/edit.erb diff --git a/lib/songify/album_repo.rb b/lib/songify/album_repo.rb index 87fa44c7..17f58788 100644 --- a/lib/songify/album_repo.rb +++ b/lib/songify/album_repo.rb @@ -3,6 +3,13 @@ module Songify class AlbumRepo + def self.add_genres(db, album_data) + album_id = album_data['id'] + album_data['genre_ids'].each do |genre_id| + db.exec("INSERT INTO album_genres (album_id, genre_id) VALUES ($1, $2)", [album_id, genre_id]) + end + end + def self.all(db) db.exec("SELECT * FROM albums").to_a end diff --git a/server.rb b/server.rb index 32eb2cca..18161012 100644 --- a/server.rb +++ b/server.rb @@ -28,7 +28,7 @@ db = Songify.create_db_connection('songify_dev') @albums = Songify::AlbumRepo.find(db, params[:id]) @songs = Songify::SongRepo.list(db, params[:id]) - @genres = Songify::GenreRepo.genres_by_album(db, params[:id]) + @genres_join = Songify::GenreRepo.genres_by_album(db, params[:id]) erb :"albums/album" end @@ -38,6 +38,25 @@ redirect to '/albums' end +get '/albums/:id/edit' do + db = Songify.create_db_connection('songify_dev') + @albums = Songify::AlbumRepo.find(db, params[:id]) + @genres_join = Songify::GenreRepo.genres_by_album(db, params[:id]) + @genres = Songify::GenreRepo.all(db) + erb :"albums/edit" +end + +post '/albums/:id/edit' do + db = Songify.create_db_connection('songify_dev') + puts params[:id].class + puts params[:genre_ids].class + Songify::AlbumRepo.add_genres(db, { + 'id' => params[:id], + 'genre_ids' => params[:genre_ids] + }) + redirect to "/albums/#{params[:id]}/edit" +end + get '/songs' do db = Songify.create_db_connection('songify_dev') @songs = Songify::SongRepo.all(db) diff --git a/views/albums/album.erb b/views/albums/album.erb index 5cc1504e..99050923 100644 --- a/views/albums/album.erb +++ b/views/albums/album.erb @@ -1,9 +1,10 @@ <- Back to Everything

    <%= @albums['title'] %> - All Songs

    -<% @genres.each do |genre| %> +<% @genres_join.each do |genre| %> <%= genre['name'] %> | <% end %> +edit

      <% if @songs.first %> @@ -18,7 +19,7 @@
      - +
      diff --git a/views/albums/edit.erb b/views/albums/edit.erb new file mode 100644 index 00000000..e4643920 --- /dev/null +++ b/views/albums/edit.erb @@ -0,0 +1,39 @@ +<- Back to Everything +

      <%= @albums['title'] %> - Edit Genres

      +

      +<% @genres_join.each do |genre| %> + <%= genre['name'] %> | +<% end %> +

      + +
      + +
      + + add genre +
      + +
      + + + \ No newline at end of file diff --git a/views/genres/genre.erb b/views/genres/genre.erb index 38afb3c4..f26d7691 100644 --- a/views/genres/genre.erb +++ b/views/genres/genre.erb @@ -14,7 +14,7 @@
      - +