From eba195913648ef64a645202a1a1c9353398f0309 Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Tue, 9 Dec 2014 13:19:31 -0800 Subject: [PATCH 1/9] songify scaffold --- Gemfile | 7 ++++++ Gemfile.lock | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ server.rb | 11 +++++++++ songify.rb | 4 ++++ spec_helper.rb | 4 ++++ 5 files changed, 88 insertions(+) create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 server.rb create mode 100644 songify.rb create mode 100644 spec_helper.rb diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..b27b6169 --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source ('http://www.rubygems.org') + +gem 'pg', '~> 0.17.1' +gem 'rspec', '~> 3.1.0' +gem 'sinatra', '~> 1.4.5' +gem 'sinatra-contrib', '~> 1.4.2' +gem 'pry-byebug', '~> 2.0.0' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..448ccca9 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,62 @@ +GEM + remote: http://www.rubygems.org/ + specs: + backports (3.6.4) + byebug (3.5.1) + columnize (~> 0.8) + debugger-linecache (~> 1.2) + slop (~> 3.6) + coderay (1.1.0) + columnize (0.9.0) + debugger-linecache (1.2.0) + diff-lcs (1.2.5) + method_source (0.8.2) + multi_json (1.10.1) + pg (0.17.1) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-byebug (2.0.0) + byebug (~> 3.4) + pry (~> 0.10) + rack (1.5.2) + rack-protection (1.5.3) + rack + rack-test (0.6.2) + rack (>= 1.0) + rspec (3.1.0) + rspec-core (~> 3.1.0) + rspec-expectations (~> 3.1.0) + rspec-mocks (~> 3.1.0) + rspec-core (3.1.7) + rspec-support (~> 3.1.0) + rspec-expectations (3.1.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.1.0) + rspec-mocks (3.1.3) + rspec-support (~> 3.1.0) + rspec-support (3.1.2) + sinatra (1.4.5) + rack (~> 1.4) + rack-protection (~> 1.4) + tilt (~> 1.3, >= 1.3.4) + sinatra-contrib (1.4.2) + backports (>= 2.0) + multi_json + rack-protection + rack-test + sinatra (~> 1.4.0) + tilt (~> 1.3) + slop (3.6.0) + tilt (1.4.1) + +PLATFORMS + ruby + +DEPENDENCIES + pg (~> 0.17.1) + pry-byebug (~> 2.0.0) + rspec (~> 3.1.0) + sinatra (~> 1.4.5) + sinatra-contrib (~> 1.4.2) diff --git a/server.rb b/server.rb new file mode 100644 index 00000000..a0dccf50 --- /dev/null +++ b/server.rb @@ -0,0 +1,11 @@ +require 'sinatra' +require 'sinatra/json' +require_relative 'songify.rb' + +set :bind, '0.0.0.0' # This is needed for Vagrant + + +get '/' do + +end + diff --git a/songify.rb b/songify.rb new file mode 100644 index 00000000..b4df398f --- /dev/null +++ b/songify.rb @@ -0,0 +1,4 @@ +module Songify +end + +# require all lib/ entities and repos files here \ No newline at end of file diff --git a/spec_helper.rb b/spec_helper.rb new file mode 100644 index 00000000..ccb3be82 --- /dev/null +++ b/spec_helper.rb @@ -0,0 +1,4 @@ +require 'rspec' +require 'pry-byebug' + +require_relative 'songify.rb' \ No newline at end of file From ba4790a480ff0d5d04acc1aa823ec9480dca0ccc Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Tue, 9 Dec 2014 16:19:43 -0800 Subject: [PATCH 2/9] artist_repo --- Gemfile | 2 +- lib/entity/artist.rb | 7 +++++ lib/repo/artist_repo.rb | 49 +++++++++++++++++++++++++++++++++++ lib/repo/repo.rb | 5 ++++ songify.rb | 4 ++- spec/entity/artist_spec.rb | 13 ++++++++++ spec/repo/artist_repo_spec.rb | 33 +++++++++++++++++++++++ spec_helper.rb | 2 +- 8 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 lib/entity/artist.rb create mode 100644 lib/repo/artist_repo.rb create mode 100644 lib/repo/repo.rb create mode 100644 spec/entity/artist_spec.rb create mode 100644 spec/repo/artist_repo_spec.rb diff --git a/Gemfile b/Gemfile index b27b6169..9cb97b9e 100644 --- a/Gemfile +++ b/Gemfile @@ -4,4 +4,4 @@ gem 'pg', '~> 0.17.1' gem 'rspec', '~> 3.1.0' gem 'sinatra', '~> 1.4.5' gem 'sinatra-contrib', '~> 1.4.2' -gem 'pry-byebug', '~> 2.0.0' +gem 'pry-byebug', '~> 2.0.0' \ No newline at end of file diff --git a/lib/entity/artist.rb b/lib/entity/artist.rb new file mode 100644 index 00000000..970d48b2 --- /dev/null +++ b/lib/entity/artist.rb @@ -0,0 +1,7 @@ +class Songify::Artist + attr_reader :name + def initialize(params) + @name = params[:name] + end + +end \ No newline at end of file diff --git a/lib/repo/artist_repo.rb b/lib/repo/artist_repo.rb new file mode 100644 index 00000000..4c378348 --- /dev/null +++ b/lib/repo/artist_repo.rb @@ -0,0 +1,49 @@ +require_relative '../../songify.rb' +require 'pg' + +class Songify::ArtistRepo + + def initialize + @db = PG.connect(dbname: 'songify-db') + end + + def create_table + command = <<-SQL + CREATE TABLE artists( + id SERIAL PRIMARY KEY, + name TEXT + ); + SQL + @db.exec(command) + end + + def add_artist(params) + command = <<-SQL + INSERT INTO artists(name) + VALUES ('#{params[:name]}') + RETURNING *; + SQL + result = @db.exec(command) + build_artist(result.first) + end + + def find_artist_by_name(params) + query = <<-SQL + SELECT * FROM artists + WHERE name = '#{params[:name]}' + SQL + result = @db.exec(command) + build_artist(result.first) + end + + def update_artist + end + + def delete_artist + end + + def build_artist(params) + Songify::Artist.new(params) + end + +end \ No newline at end of file diff --git a/lib/repo/repo.rb b/lib/repo/repo.rb new file mode 100644 index 00000000..0f9e832e --- /dev/null +++ b/lib/repo/repo.rb @@ -0,0 +1,5 @@ +class Songify::Repo + def initialize + @db = PG.connect(dbname: 'songify-db') + end +end \ No newline at end of file diff --git a/songify.rb b/songify.rb index b4df398f..89c6eaf5 100644 --- a/songify.rb +++ b/songify.rb @@ -1,4 +1,6 @@ module Songify end -# require all lib/ entities and repos files here \ No newline at end of file +# require all lib/ entities and repos files here +require_relative 'lib/entity/artist.rb' +require_relative 'lib/repo/artist_repo.rb' \ No newline at end of file diff --git a/spec/entity/artist_spec.rb b/spec/entity/artist_spec.rb new file mode 100644 index 00000000..e2e66ac8 --- /dev/null +++ b/spec/entity/artist_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper.rb' + +describe 'the artist class' do + + before(:each) do + @artist = Songify::Artist.new({name: 'Seal'}) + end + + it 'should have a name' do + expect(@artist.name).to eq('Seal') + end + +end \ No newline at end of file diff --git a/spec/repo/artist_repo_spec.rb b/spec/repo/artist_repo_spec.rb new file mode 100644 index 00000000..fe220907 --- /dev/null +++ b/spec/repo/artist_repo_spec.rb @@ -0,0 +1,33 @@ +require_relative '../../spec_helper.rb' + +describe 'the artist repo' do + before(:each) do + @artist_repo = Songify::ArtistRepo.new + end + + it 'can add an artist to the database' do + result = @artist_repo.add_new_artist({name: 'Willie Nelson'}) + artists = @artist_repo.get_all + expect(result.name).to eq('Willie Nelson') + expect(artists.length).to eq(1) + end + + it 'can find an artist by name' do + @artist_repo.add_new_artist({name: 'Johnny Cash'}) + result = @artist_repo.find_artist_by_name({name: 'Johnny Cash'}) + expect(result.name).to eq('Johnny Cash') + expect(result.id).to eq(2) + end + + it 'can edit an artist' do + result = @artist_repo.update_listing({id: 2, name: "John Cash"}) + expect(result.id).to eq(2) + expect(result.name).to eq("John Cash") + end + + it 'can delete an artist from the database' do + @artist_repo.delete({id: 1}) + artists = @artist_repo.get_all + expect(artists.length).to eq(1) + end +end \ No newline at end of file diff --git a/spec_helper.rb b/spec_helper.rb index ccb3be82..c1681409 100644 --- a/spec_helper.rb +++ b/spec_helper.rb @@ -1,4 +1,4 @@ require 'rspec' -require 'pry-byebug' +# require 'pry-byebug' require_relative 'songify.rb' \ No newline at end of file From 0ebb7fb631a645d8721f0974189f2e7f511b0641 Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Tue, 9 Dec 2014 17:20:31 -0800 Subject: [PATCH 3/9] added get_all artists --- lib/repo/artist_repo.rb | 12 ++++++++++++ spec/repo/artist_repo_spec.rb | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/repo/artist_repo.rb b/lib/repo/artist_repo.rb index 4c378348..d12cc662 100644 --- a/lib/repo/artist_repo.rb +++ b/lib/repo/artist_repo.rb @@ -36,6 +36,18 @@ def find_artist_by_name(params) build_artist(result.first) end + def get_all + query = <<-SQL + SELECT * FROM artists + SQL + result = @db.exec(command) + artists = [] + result.each do |res| + artists << build_artist(res) + end + end + + def update_artist end diff --git a/spec/repo/artist_repo_spec.rb b/spec/repo/artist_repo_spec.rb index fe220907..01232eb5 100644 --- a/spec/repo/artist_repo_spec.rb +++ b/spec/repo/artist_repo_spec.rb @@ -19,13 +19,13 @@ expect(result.id).to eq(2) end - it 'can edit an artist' do + xit 'can edit an artist' do result = @artist_repo.update_listing({id: 2, name: "John Cash"}) expect(result.id).to eq(2) expect(result.name).to eq("John Cash") end - it 'can delete an artist from the database' do + xit 'can delete an artist from the database' do @artist_repo.delete({id: 1}) artists = @artist_repo.get_all expect(artists.length).to eq(1) From 5254265962b5d3c5bbb49475616db20c0e53e6d2 Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Tue, 9 Dec 2014 19:40:24 -0800 Subject: [PATCH 4/9] byebug v 1.3.3 --- Gemfile | 2 +- Gemfile.lock | 11 +++++------ lib/repo/artist_repo.rb | 4 ++-- spec/repo/artist_repo_spec.rb | 1 + spec_helper.rb | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index 9cb97b9e..446d119d 100644 --- a/Gemfile +++ b/Gemfile @@ -4,4 +4,4 @@ gem 'pg', '~> 0.17.1' gem 'rspec', '~> 3.1.0' gem 'sinatra', '~> 1.4.5' gem 'sinatra-contrib', '~> 1.4.2' -gem 'pry-byebug', '~> 2.0.0' \ No newline at end of file +gem 'pry-byebug', '~> 1.3.3' diff --git a/Gemfile.lock b/Gemfile.lock index 448ccca9..8e25f483 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,10 +2,9 @@ GEM remote: http://www.rubygems.org/ specs: backports (3.6.4) - byebug (3.5.1) - columnize (~> 0.8) + byebug (2.7.0) + columnize (~> 0.3) debugger-linecache (~> 1.2) - slop (~> 3.6) coderay (1.1.0) columnize (0.9.0) debugger-linecache (1.2.0) @@ -17,8 +16,8 @@ GEM coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - pry-byebug (2.0.0) - byebug (~> 3.4) + pry-byebug (1.3.3) + byebug (~> 2.7) pry (~> 0.10) rack (1.5.2) rack-protection (1.5.3) @@ -56,7 +55,7 @@ PLATFORMS DEPENDENCIES pg (~> 0.17.1) - pry-byebug (~> 2.0.0) + pry-byebug (~> 1.3.3) rspec (~> 3.1.0) sinatra (~> 1.4.5) sinatra-contrib (~> 1.4.2) diff --git a/lib/repo/artist_repo.rb b/lib/repo/artist_repo.rb index d12cc662..42b9e1dd 100644 --- a/lib/repo/artist_repo.rb +++ b/lib/repo/artist_repo.rb @@ -32,7 +32,7 @@ def find_artist_by_name(params) SELECT * FROM artists WHERE name = '#{params[:name]}' SQL - result = @db.exec(command) + result = @db.exec(query) build_artist(result.first) end @@ -40,7 +40,7 @@ def get_all query = <<-SQL SELECT * FROM artists SQL - result = @db.exec(command) + result = @db.exec(query) artists = [] result.each do |res| artists << build_artist(res) diff --git a/spec/repo/artist_repo_spec.rb b/spec/repo/artist_repo_spec.rb index 01232eb5..74727d93 100644 --- a/spec/repo/artist_repo_spec.rb +++ b/spec/repo/artist_repo_spec.rb @@ -7,6 +7,7 @@ it 'can add an artist to the database' do result = @artist_repo.add_new_artist({name: 'Willie Nelson'}) + binding.pry artists = @artist_repo.get_all expect(result.name).to eq('Willie Nelson') expect(artists.length).to eq(1) diff --git a/spec_helper.rb b/spec_helper.rb index c1681409..ccb3be82 100644 --- a/spec_helper.rb +++ b/spec_helper.rb @@ -1,4 +1,4 @@ require 'rspec' -# require 'pry-byebug' +require 'pry-byebug' require_relative 'songify.rb' \ No newline at end of file From af2f00e13ce220a90182b50c85178e1dc028f060 Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Wed, 10 Dec 2014 08:58:49 -0800 Subject: [PATCH 5/9] artist repo --- lib/entity/artist.rb | 5 ++- lib/repo/artist_repo.rb | 43 +++++++++++++++----- server.rb | 4 +- spec/entity/artist_spec.rb | 2 +- spec/repo/artist_repo_spec.rb | 75 +++++++++++++++++++++++++---------- 5 files changed, 95 insertions(+), 34 deletions(-) diff --git a/lib/entity/artist.rb b/lib/entity/artist.rb index 970d48b2..e89a4347 100644 --- a/lib/entity/artist.rb +++ b/lib/entity/artist.rb @@ -1,7 +1,8 @@ class Songify::Artist - attr_reader :name + attr_reader :name, :id def initialize(params) - @name = params[:name] + @name = params['name'] + @id = params['id'].to_i end end \ No newline at end of file diff --git a/lib/repo/artist_repo.rb b/lib/repo/artist_repo.rb index 42b9e1dd..4148cc04 100644 --- a/lib/repo/artist_repo.rb +++ b/lib/repo/artist_repo.rb @@ -7,9 +7,16 @@ def initialize @db = PG.connect(dbname: 'songify-db') end + def drop_table + command = <<-SQL + DROP TABLE IF EXISTS artists + SQL + @db.exec(command) + end + def create_table command = <<-SQL - CREATE TABLE artists( + CREATE TABLE IF NOT EXISTS artists( id SERIAL PRIMARY KEY, name TEXT ); @@ -17,11 +24,11 @@ def create_table @db.exec(command) end - def add_artist(params) + def add_new_artist(params) command = <<-SQL - INSERT INTO artists(name) - VALUES ('#{params[:name]}') - RETURNING *; + INSERT INTO artists(name) + VALUES ('#{params[:name]}') + RETURNING *; SQL result = @db.exec(command) build_artist(result.first) @@ -29,8 +36,8 @@ def add_artist(params) def find_artist_by_name(params) query = <<-SQL - SELECT * FROM artists - WHERE name = '#{params[:name]}' + SELECT * FROM artists + WHERE name = '#{params[:name]}' SQL result = @db.exec(query) build_artist(result.first) @@ -38,20 +45,36 @@ def find_artist_by_name(params) def get_all query = <<-SQL - SELECT * FROM artists + SELECT * FROM artists SQL result = @db.exec(query) artists = [] result.each do |res| artists << build_artist(res) end + return artists end - def update_artist + def update_artist(params) + command = <<-SQL + UPDATE artists + SET name = '#{params[:name]}' + WHERE id = '#{params[:id]}' + RETURNING *; + SQL + result = @db.exec(command) + build_artist(result.first) end - def delete_artist + def delete_artist(params) + command = <<-SQL + DELETE FROM artists + WHERE (id = '#{params[:id]}') OR (name = '#{params[:name]}') + RETURNING *; + SQL + result = @db.exec(command) + build_artist(result.first) end def build_artist(params) diff --git a/server.rb b/server.rb index a0dccf50..0093b4ac 100644 --- a/server.rb +++ b/server.rb @@ -1,11 +1,13 @@ require 'sinatra' require 'sinatra/json' +require "sinatra/reloader" if development? + require_relative 'songify.rb' set :bind, '0.0.0.0' # This is needed for Vagrant get '/' do - + "Hello World Whats UP" end diff --git a/spec/entity/artist_spec.rb b/spec/entity/artist_spec.rb index e2e66ac8..4e52f067 100644 --- a/spec/entity/artist_spec.rb +++ b/spec/entity/artist_spec.rb @@ -3,7 +3,7 @@ describe 'the artist class' do before(:each) do - @artist = Songify::Artist.new({name: 'Seal'}) + @artist = Songify::Artist.new({'name'=> 'Seal'}) end it 'should have a name' do diff --git a/spec/repo/artist_repo_spec.rb b/spec/repo/artist_repo_spec.rb index 74727d93..3f79ab10 100644 --- a/spec/repo/artist_repo_spec.rb +++ b/spec/repo/artist_repo_spec.rb @@ -1,34 +1,69 @@ require_relative '../../spec_helper.rb' describe 'the artist repo' do + let(:artist_repo) { + Songify::ArtistRepo.new + } before(:each) do - @artist_repo = Songify::ArtistRepo.new + artist_repo.drop_table + artist_repo.create_table end - it 'can add an artist to the database' do - result = @artist_repo.add_new_artist({name: 'Willie Nelson'}) - binding.pry - artists = @artist_repo.get_all - expect(result.name).to eq('Willie Nelson') - expect(artists.length).to eq(1) + describe 'adding' do + it 'can add an artist to the database' do + result = artist_repo.add_new_artist({name: 'Willie Nelson'}) + artists = artist_repo.get_all + expect(result.name).to eq('Willie Nelson') + expect(artists.length).to eq(1) + end end - it 'can find an artist by name' do - @artist_repo.add_new_artist({name: 'Johnny Cash'}) - result = @artist_repo.find_artist_by_name({name: 'Johnny Cash'}) - expect(result.name).to eq('Johnny Cash') - expect(result.id).to eq(2) + describe 'finding' do + before(:each) do + artist_repo.add_new_artist({name: 'Willie Nelson'}) + artist_repo.add_new_artist({name: 'Johnny Cash'}) + end + + it 'can find an artist by name' do + result = artist_repo.find_artist_by_name({name: 'Johnny Cash'}) + expect(result.name).to eq('Johnny Cash') + expect(result.id).to eq(2) + end + + xit 'can find an artist by id' do + end + + xit 'can find all artists' do + end end - xit 'can edit an artist' do - result = @artist_repo.update_listing({id: 2, name: "John Cash"}) - expect(result.id).to eq(2) - expect(result.name).to eq("John Cash") + describe 'editing' do + it 'can edit an artist' do + artist_repo.add_new_artist({name: 'Johnny Cash'}) + result = artist_repo.update_artist({id: 1, name: "John Cash"}) + expect(result.id).to eq(1) + expect(result.name).to eq("John Cash") + end end + - xit 'can delete an artist from the database' do - @artist_repo.delete({id: 1}) - artists = @artist_repo.get_all - expect(artists.length).to eq(1) + describe 'delete' do + before(:each) do + artist_repo.add_new_artist({name: 'Willie Nelson'}) + artist_repo.add_new_artist({name: 'Johnny Cash'}) + end + + it 'can delete an artist from the database using id' do + artist_repo.delete_artist({id: 1}) + artists = artist_repo.get_all + expect(artists.length).to eq(1) + end + + it 'can delete an artist from the database using name' do + artist_repo.delete_artist({name: 'Johhny Cash'}) + artists = artist_repo.get_all + expect(artists.length).to eq(1) + end end + end \ No newline at end of file From 347ce4d7673857f0135a0c498accd55a3351cd07 Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Wed, 10 Dec 2014 14:55:07 -0800 Subject: [PATCH 6/9] started album --- lib/entity/album.rb | 11 +++++++++++ lib/repo/album_repo.rb | 0 songify.rb | 5 ++++- spec/entity/album_spec.rb | 14 ++++++++++++++ spec/repo/album_repo_spec.rb | 0 5 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 lib/entity/album.rb create mode 100644 lib/repo/album_repo.rb create mode 100644 spec/entity/album_spec.rb create mode 100644 spec/repo/album_repo_spec.rb diff --git a/lib/entity/album.rb b/lib/entity/album.rb new file mode 100644 index 00000000..a890fd28 --- /dev/null +++ b/lib/entity/album.rb @@ -0,0 +1,11 @@ +class Songify::Album + + attr_reader :title, :artist, :cover + + def initialize(params) + @title = params[:title] + @artist = params[:artist] + @cover = params[:cover] + end + +end \ No newline at end of file diff --git a/lib/repo/album_repo.rb b/lib/repo/album_repo.rb new file mode 100644 index 00000000..e69de29b diff --git a/songify.rb b/songify.rb index 89c6eaf5..7f85d0a7 100644 --- a/songify.rb +++ b/songify.rb @@ -3,4 +3,7 @@ module Songify # require all lib/ entities and repos files here require_relative 'lib/entity/artist.rb' -require_relative 'lib/repo/artist_repo.rb' \ No newline at end of file +require_relative 'lib/entity/album.rb' + +require_relative 'lib/repo/artist_repo.rb' +require_relative 'lib/repo/album_repo.rb' \ No newline at end of file diff --git a/spec/entity/album_spec.rb b/spec/entity/album_spec.rb new file mode 100644 index 00000000..9a5303cb --- /dev/null +++ b/spec/entity/album_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../spec_helper.rb' + +describe 'an album' do + let(:album) {Songify::Album.new( + {title: 'Darkness on the Edge of Town', + artist: 'Bruce Springsteen', + cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' + })} + it 'has a title, an artist, and a cover' do + expect(album.title).to eq('Darkness on the Edge of Town') + expect(album.artist).to eq('Bruce Springsteen') + expect(album.cover).to eq('http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg') + end +end \ No newline at end of file diff --git a/spec/repo/album_repo_spec.rb b/spec/repo/album_repo_spec.rb new file mode 100644 index 00000000..e69de29b From f9c754c21499df9fcc57438c433c3b318fecadc0 Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Thu, 11 Dec 2014 17:57:27 -0800 Subject: [PATCH 7/9] artists all the way --- Gemfile | 1 + Gemfile.lock | 2 + Rakefile | 40 +++++++++++++ lib/entity/album.rb | 3 +- lib/repo/album_repo.rb | 80 +++++++++++++++++++++++++ lib/repo/artist_repo.rb | 2 +- public/assets/plus_sign.png | Bin 0 -> 24925 bytes public/css/main.css | 20 +++++++ server.rb | 9 ++- songify.rb | 1 + spec/entity/album_spec.rb | 6 +- spec/repo/album_repo_spec.rb | 106 ++++++++++++++++++++++++++++++++++ spec/repo/artist_repo_spec.rb | 6 -- views/index.erb | 28 +++++++++ views/layout.erb | 12 ++++ 15 files changed, 305 insertions(+), 11 deletions(-) create mode 100644 Rakefile create mode 100644 public/assets/plus_sign.png create mode 100644 public/css/main.css create mode 100644 views/index.erb create mode 100644 views/layout.erb diff --git a/Gemfile b/Gemfile index 446d119d..da476bb8 100644 --- a/Gemfile +++ b/Gemfile @@ -5,3 +5,4 @@ gem 'rspec', '~> 3.1.0' gem 'sinatra', '~> 1.4.5' gem 'sinatra-contrib', '~> 1.4.2' gem 'pry-byebug', '~> 1.3.3' +gem 'rake', '~> 10.4.2' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 8e25f483..3065f990 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -24,6 +24,7 @@ GEM rack rack-test (0.6.2) rack (>= 1.0) + rake (10.4.2) rspec (3.1.0) rspec-core (~> 3.1.0) rspec-expectations (~> 3.1.0) @@ -56,6 +57,7 @@ PLATFORMS DEPENDENCIES pg (~> 0.17.1) pry-byebug (~> 1.3.3) + rake (~> 10.4.2) rspec (~> 3.1.0) sinatra (~> 1.4.5) sinatra-contrib (~> 1.4.2) diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..497ed2ca --- /dev/null +++ b/Rakefile @@ -0,0 +1,40 @@ +require_relative 'spec_helper.rb' + +@album_repo = Songify::AlbumRepo.new + +task :seed do + @album_repo.drop_table + puts 'table dropped' + @album_repo.create_table + puts 'table created' + @album_repo.add_new_album( + {title: 'Darkness on the Edge of Town', + artist: 'Bruce Springsteen', + cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' + }) + puts 'seeding bruce' + @album_repo.add_new_album( + {title: 'Pet Sounds', + artist: 'The Beach Boys', + cover: 'http://upload.wikimedia.org/wikipedia/en/b/bb/PetSoundsCover.jpg' + }) + puts 'seeding the beach boys' + @album_repo.add_new_album( + {title: 'Run The Jewels 2', + artist: 'Killer Mike & El P', + cover: 'http://36.media.tumblr.com/4d1d4fa86923323f2686e9f8baacfd23/tumblr_ngbryfp3IH1t00btlo1_1280.jpg' + }) + puts 'seeding RTJ2' + @album_repo.add_new_album( + {title: 'Quality Street', + artist: 'Nick Lowe', + cover: 'http://ecx.images-amazon.com/images/I/91ZdT8CmwiL._SX425_.jpg' + }) + puts 'seeding chrimbo' + @album_repo.add_new_album({ + title: 'Summerteeth', + artist: 'Wilco', + cover: 'http://ecx.images-amazon.com/images/I/51bJzaovu7L.jpg' + }) + puts 'seeding Wilco' +end \ No newline at end of file diff --git a/lib/entity/album.rb b/lib/entity/album.rb index a890fd28..0307d72b 100644 --- a/lib/entity/album.rb +++ b/lib/entity/album.rb @@ -1,11 +1,12 @@ class Songify::Album - attr_reader :title, :artist, :cover + attr_reader :title, :artist, :cover, :id def initialize(params) @title = params[:title] @artist = params[:artist] @cover = params[:cover] + @id = params[:id].to_i end end \ No newline at end of file diff --git a/lib/repo/album_repo.rb b/lib/repo/album_repo.rb index e69de29b..d3b2fcee 100644 --- a/lib/repo/album_repo.rb +++ b/lib/repo/album_repo.rb @@ -0,0 +1,80 @@ +class Songify::AlbumRepo < Songify::Repo + + def create_table + command = <<-SQL + CREATE TABLE IF NOT EXISTS + albums( + id SERIAL PRIMARY KEY, + title TEXT, + artist TEXT, + cover TEXT + ); + SQL + @db.exec(command) + end + + def drop_table + command = <<-SQL + DROP TABLE IF EXISTS albums CASCADE; + SQL + @db.exec(command) + end + + def add_new_album(params) + command = <<-SQL + INSERT INTO albums + (title, artist, cover) + VALUES ('#{params[:title]}', '#{params[:artist]}', '#{params[:cover]}') + RETURNING *; + SQL + result = @db.exec(command).first + build_album(result) + end + + def build_album(params) + new_params = {} + params.each_pair {|k,v| new_params[k.to_sym] = v} + Songify::Album.new(new_params) + end + + def find_album(params) + col = params.keys.first + val = params[col] + query = <<-SQL + SELECT * FROM albums + WHERE #{col} = '#{val}' + SQL + result = @db.exec(query).to_a + result.map {|album| build_album(album)} + end + + def get_all_albums + query = <<-SQL + SELECT * FROM albums; + SQL + result = @db.exec(query).to_a + result.map{|album| build_album(album)} + end + + def update_album(params) + command = <<-SQL + UPDATE albums + SET (title, artist, cover) = ('#{params[:title]}', '#{params[:artist]}', '#{params[:cover]}') + WHERE id = #{params[:id]} + RETURNING *; + SQL + result = @db.exec(command).first + build_album(result) + end + + def delete_album(params) + command = <<-SQL + DELETE FROM albums + WHERE id = '#{params[:id]}' + RETURNING *; + SQL + result = @db.exec(command).first + build_album(result) + end + +end \ No newline at end of file diff --git a/lib/repo/artist_repo.rb b/lib/repo/artist_repo.rb index 4148cc04..78538462 100644 --- a/lib/repo/artist_repo.rb +++ b/lib/repo/artist_repo.rb @@ -70,7 +70,7 @@ def update_artist(params) def delete_artist(params) command = <<-SQL DELETE FROM artists - WHERE (id = '#{params[:id]}') OR (name = '#{params[:name]}') + WHERE id = '#{params[:id]}' RETURNING *; SQL result = @db.exec(command) diff --git a/public/assets/plus_sign.png b/public/assets/plus_sign.png new file mode 100644 index 0000000000000000000000000000000000000000..715cc9301136f0f48c291dca977075782c2607cd GIT binary patch literal 24925 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 N=xG_D$~5dE{s-BwN3Z|@ literal 0 HcmV?d00001 diff --git a/public/css/main.css b/public/css/main.css new file mode 100644 index 00000000..1d545970 --- /dev/null +++ b/public/css/main.css @@ -0,0 +1,20 @@ +a { + text-decoration: none; + color: black; +} +.album-wrapper { + text-align: center; + letter-spacing: 0; +} + +.album-cover { + margin: auto; +} + +.album-artist { + padding-bottom: 5%; +} + +img { + max-width: 90%; +} \ No newline at end of file diff --git a/server.rb b/server.rb index 0093b4ac..21ac987b 100644 --- a/server.rb +++ b/server.rb @@ -6,8 +6,15 @@ set :bind, '0.0.0.0' # This is needed for Vagrant +album_repo = Songify::AlbumRepo.new get '/' do - "Hello World Whats UP" + @albums = album_repo.get_all_albums + erb :index +end + +post '/' do + album_repo.add_new_album(params) + redirect to('/') end diff --git a/songify.rb b/songify.rb index 7f85d0a7..41760d71 100644 --- a/songify.rb +++ b/songify.rb @@ -5,5 +5,6 @@ module Songify require_relative 'lib/entity/artist.rb' require_relative 'lib/entity/album.rb' +require_relative 'lib/repo/repo.rb' require_relative 'lib/repo/artist_repo.rb' require_relative 'lib/repo/album_repo.rb' \ No newline at end of file diff --git a/spec/entity/album_spec.rb b/spec/entity/album_spec.rb index 9a5303cb..205a6280 100644 --- a/spec/entity/album_spec.rb +++ b/spec/entity/album_spec.rb @@ -1,11 +1,13 @@ require_relative '../../spec_helper.rb' describe 'an album' do - let(:album) {Songify::Album.new( + let(:album) { + Songify::Album.new( {title: 'Darkness on the Edge of Town', artist: 'Bruce Springsteen', cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' - })} + }) + } it 'has a title, an artist, and a cover' do expect(album.title).to eq('Darkness on the Edge of Town') expect(album.artist).to eq('Bruce Springsteen') diff --git a/spec/repo/album_repo_spec.rb b/spec/repo/album_repo_spec.rb index e69de29b..bcdc322c 100644 --- a/spec/repo/album_repo_spec.rb +++ b/spec/repo/album_repo_spec.rb @@ -0,0 +1,106 @@ +require_relative '../../spec_helper.rb' + +describe 'the album repo' do + let(:album_repo){ + Songify::AlbumRepo.new + } + + before(:each){ + album_repo.drop_table + album_repo.create_table + } + + describe 'add new album' do + it 'should be able to add an album' do + result = album_repo.add_new_album( + {title: 'Darkness on the Edge of Town', + artist: 'Bruce Springsteen', + cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' + }) + albums = album_repo.get_all_albums + expect(result.title).to eq('Darkness on the Edge of Town') + expect(albums.length).to eq(1) + end + end + + describe 'read, update, delete' do + before(:each) do + album_repo.add_new_album( + {title: 'Darkness on the Edge of Town', + artist: 'Bruce Springsteen', + cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' + }) + album_repo.add_new_album( + {title: 'Pet Sounds', + artist: 'The Beach Boys', + cover: 'http://upload.wikimedia.org/wikipedia/en/b/bb/PetSoundsCover.jpg' + }) + album_repo.add_new_album( + {title: 'Run The Jewels 2', + artist: 'Killer Mike & El P', + cover: 'http://36.media.tumblr.com/4d1d4fa86923323f2686e9f8baacfd23/tumblr_ngbryfp3IH1t00btlo1_1280.jpg' + }) + album_repo.add_new_album( + {title: 'Run The Jewels 2', + artist: 'Killer Mike & El P', + cover: 'http://36.media.tumblr.com/4d1d4fa86923323f2686e9f8baacfd23/tumblr_ngbryfp3IH1t00btlo1_1280.jpg' + }) + end + + it 'should be able to find an album by id' do + result = album_repo.find_album({id: 1}) + expect(result.first.artist).to eq('Bruce Springsteen') + end + + it 'should be able to find an album by title' do + result = album_repo.find_album({title: 'Pet Sounds'}) + expect(result.first.id).to eq(2) + end + + it 'should be able to find multiple albums of the same title' do + result = album_repo.find_album({title: "Run The Jewels 2"}) + res_arr = [] + expect(result.length).to eq(2) + result.each{|x| res_arr << x.id} + expect(res_arr).to eq([3,4]) + end + + describe 'update' do + it 'can update an album' do + result = album_repo.update_album({id: 1, title: 'Born To Run', artist: 'Bruce Springsteen', cover: 'www.some_cover.jpg'}) + expect(result.title).to eq('Born To Run') + end + + it 'can update the artist' do + result = album_repo.update_album({id: 2, artist: 'TBB', title: 'Pet Sounds', cover: 'some_cover.jpg'}) + expect(result.artist).to eq('TBB') + expect(result.title).to eq('Pet Sounds') + end + + it 'can update the cover' do + result = album_repo.update_album({id: 3, artist: 'Killer Mike & El P', title: 'RTJ2', cover: 'test.jpg'}) + expect(result.artist).to eq('Killer Mike & El P') + expect(result.cover).to eq('test.jpg') + end + + it 'can update multiple params' do + result = album_repo.update_album({id: 4, artist: 'KMEP', title: 'RTJ2', cover: 'some_cover.jpg'}) + expect(result.artist).to eq('KMEP') + expect(result.title).to eq('RTJ2') + expect(result.id).to eq(4) + end + + end + + describe 'delete' do + it 'can delete an album' do + result = album_repo.delete_album({id: 2}) + expect(result.title).to eq('Pet Sounds') + albums = album_repo.get_all_albums + expect(albums.length).to eq(3) + end + end + end + + +end \ No newline at end of file diff --git a/spec/repo/artist_repo_spec.rb b/spec/repo/artist_repo_spec.rb index 3f79ab10..84aa1c10 100644 --- a/spec/repo/artist_repo_spec.rb +++ b/spec/repo/artist_repo_spec.rb @@ -58,12 +58,6 @@ artists = artist_repo.get_all expect(artists.length).to eq(1) end - - it 'can delete an artist from the database using name' do - artist_repo.delete_artist({name: 'Johhny Cash'}) - artists = artist_repo.get_all - expect(artists.length).to eq(1) - end end end \ No newline at end of file diff --git a/views/index.erb b/views/index.erb new file mode 100644 index 00000000..22101564 --- /dev/null +++ b/views/index.erb @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/views/layout.erb b/views/layout.erb new file mode 100644 index 00000000..cb4287df --- /dev/null +++ b/views/layout.erb @@ -0,0 +1,12 @@ + + + + Codestin Search App + + + + + + <%= yield %> + + \ No newline at end of file From 913a899afcfb016a530bd9a13a1a37f56443853c Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Sun, 14 Dec 2014 16:34:08 -0800 Subject: [PATCH 8/9] albums and songs --- Rakefile | 7 ++- lib/entity/artist.rb | 8 --- lib/entity/song.rb | 11 ++++ lib/repo/album_repo.rb | 10 ++-- lib/repo/artist_repo.rb | 84 ------------------------------- lib/repo/repo.rb | 2 + lib/repo/song_repo.rb | 78 ++++++++++++++++++++++++++++ public/css/main.css | 3 ++ server.rb | 12 ++++- songify.rb | 6 +-- spec/entity/artist_spec.rb | 13 ----- spec/entity/song_spec.rb | 22 ++++++++ spec/repo/artist_repo_spec.rb | 63 ----------------------- spec/repo/song_repo_spec.rb | 95 +++++++++++++++++++++++++++++++++++ views/album.erb | 24 +++++++++ views/index.erb | 20 ++++---- 16 files changed, 269 insertions(+), 189 deletions(-) delete mode 100644 lib/entity/artist.rb create mode 100644 lib/entity/song.rb delete mode 100644 lib/repo/artist_repo.rb create mode 100644 lib/repo/song_repo.rb delete mode 100644 spec/entity/artist_spec.rb create mode 100644 spec/entity/song_spec.rb delete mode 100644 spec/repo/artist_repo_spec.rb create mode 100644 spec/repo/song_repo_spec.rb create mode 100644 views/album.erb diff --git a/Rakefile b/Rakefile index 497ed2ca..ca46b5e8 100644 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,15 @@ require_relative 'spec_helper.rb' @album_repo = Songify::AlbumRepo.new +@song_repo = Songify::SongRepo.new task :seed do @album_repo.drop_table - puts 'table dropped' + @song_repo.drop_table + puts 'tables dropped' @album_repo.create_table - puts 'table created' + @song_repo.create_table + puts 'tables created' @album_repo.add_new_album( {title: 'Darkness on the Edge of Town', artist: 'Bruce Springsteen', diff --git a/lib/entity/artist.rb b/lib/entity/artist.rb deleted file mode 100644 index e89a4347..00000000 --- a/lib/entity/artist.rb +++ /dev/null @@ -1,8 +0,0 @@ -class Songify::Artist - attr_reader :name, :id - def initialize(params) - @name = params['name'] - @id = params['id'].to_i - end - -end \ No newline at end of file diff --git a/lib/entity/song.rb b/lib/entity/song.rb new file mode 100644 index 00000000..11c5834d --- /dev/null +++ b/lib/entity/song.rb @@ -0,0 +1,11 @@ +class Songify::Song + + attr_reader :name, :album_id, :id, :embed + + def initialize(params) + @name = params[:name] + @album_id = params[:album_id].to_i + @embed = params[:embed] + @id = params[:id].to_i + end +end \ No newline at end of file diff --git a/lib/repo/album_repo.rb b/lib/repo/album_repo.rb index d3b2fcee..764658de 100644 --- a/lib/repo/album_repo.rb +++ b/lib/repo/album_repo.rb @@ -32,17 +32,15 @@ def add_new_album(params) end def build_album(params) - new_params = {} - params.each_pair {|k,v| new_params[k.to_sym] = v} - Songify::Album.new(new_params) + Songify::Album.new(Hash[params.map{|k,v| [k.to_sym, v]}]) end def find_album(params) col = params.keys.first val = params[col] query = <<-SQL - SELECT * FROM albums - WHERE #{col} = '#{val}' + SELECT * FROM albums + WHERE #{col} = '#{val}' SQL result = @db.exec(query).to_a result.map {|album| build_album(album)} @@ -70,7 +68,7 @@ def update_album(params) def delete_album(params) command = <<-SQL DELETE FROM albums - WHERE id = '#{params[:id]}' + WHERE id = #{params[:id]} RETURNING *; SQL result = @db.exec(command).first diff --git a/lib/repo/artist_repo.rb b/lib/repo/artist_repo.rb deleted file mode 100644 index 78538462..00000000 --- a/lib/repo/artist_repo.rb +++ /dev/null @@ -1,84 +0,0 @@ -require_relative '../../songify.rb' -require 'pg' - -class Songify::ArtistRepo - - def initialize - @db = PG.connect(dbname: 'songify-db') - end - - def drop_table - command = <<-SQL - DROP TABLE IF EXISTS artists - SQL - @db.exec(command) - end - - def create_table - command = <<-SQL - CREATE TABLE IF NOT EXISTS artists( - id SERIAL PRIMARY KEY, - name TEXT - ); - SQL - @db.exec(command) - end - - def add_new_artist(params) - command = <<-SQL - INSERT INTO artists(name) - VALUES ('#{params[:name]}') - RETURNING *; - SQL - result = @db.exec(command) - build_artist(result.first) - end - - def find_artist_by_name(params) - query = <<-SQL - SELECT * FROM artists - WHERE name = '#{params[:name]}' - SQL - result = @db.exec(query) - build_artist(result.first) - end - - def get_all - query = <<-SQL - SELECT * FROM artists - SQL - result = @db.exec(query) - artists = [] - result.each do |res| - artists << build_artist(res) - end - return artists - end - - - def update_artist(params) - command = <<-SQL - UPDATE artists - SET name = '#{params[:name]}' - WHERE id = '#{params[:id]}' - RETURNING *; - SQL - result = @db.exec(command) - build_artist(result.first) - end - - def delete_artist(params) - command = <<-SQL - DELETE FROM artists - WHERE id = '#{params[:id]}' - RETURNING *; - SQL - result = @db.exec(command) - build_artist(result.first) - end - - def build_artist(params) - Songify::Artist.new(params) - end - -end \ No newline at end of file diff --git a/lib/repo/repo.rb b/lib/repo/repo.rb index 0f9e832e..7cbbd4b2 100644 --- a/lib/repo/repo.rb +++ b/lib/repo/repo.rb @@ -1,3 +1,5 @@ +require 'pg' + class Songify::Repo def initialize @db = PG.connect(dbname: 'songify-db') diff --git a/lib/repo/song_repo.rb b/lib/repo/song_repo.rb new file mode 100644 index 00000000..9408d357 --- /dev/null +++ b/lib/repo/song_repo.rb @@ -0,0 +1,78 @@ +class Songify::SongRepo < Songify::Repo + + def create_table + command = <<-SQL + CREATE TABLE IF NOT EXISTS + songs( + id SERIAL PRIMARY KEY, + name TEXT, + embed TEXT, + album_id INTEGER REFERENCES albums (id) + ); + SQL + @db.exec(command) + end + + def drop_table + command = <<-SQL + DROP TABLE IF EXISTS songs CASCADE; + SQL + @db.exec(command) + end + + def add_new_song(params) + command = <<-SQL + INSERT INTO songs + (name, album_id, embed) + VALUES ('#{params[:name]}', #{params[:album_id]}, '#{params[:embed]}') + RETURNING *; + SQL + result = @db.exec(command).first + build_song(result) + end + + def build_song(params) + Songify::Song.new(Hash[params.map{|k,v| [k.to_sym, v]}]) + end + + def get_all_songs + query = <<-SQL + SELECT * FROM songs; + SQL + results = @db.exec(query).to_a + results.map{|song| build_song(song)} + end + + def find_songs(params) + col = params.keys.first + val = params[col] + query = <<-SQL + SELECT * FROM songs + WHERE #{col} = '#{val}' + SQL + result = @db.exec(query).to_a + result.map{|song| build_song(song)} + end + + def update_song(params) + command = <<-SQL + UPDATE songs + SET (name, album_id, embed) = ('#{params[:name]}', #{params[:album_id]}, '#{params[:embed]}') + WHERE id = #{params[:id]} + RETURNING *; + SQL + result = @db.exec(command).first + build_song(result) + end + + def delete_song(params) + command = <<-SQL + DELETE FROM songs + WHERE id = #{params[:id]} + RETURNING *; + SQL + result = @db.exec(command).first + build_song(result) + end + +end \ No newline at end of file diff --git a/public/css/main.css b/public/css/main.css index 1d545970..6bcbee0f 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -15,6 +15,9 @@ a { padding-bottom: 5%; } +.add-inner, .edit-inner { + padding: 5px; +} img { max-width: 90%; } \ No newline at end of file diff --git a/server.rb b/server.rb index 21ac987b..4464e713 100644 --- a/server.rb +++ b/server.rb @@ -1,12 +1,14 @@ require 'sinatra' require 'sinatra/json' -require "sinatra/reloader" if development? +require 'sinatra/reloader' if development? +require 'pry-byebug' require_relative 'songify.rb' set :bind, '0.0.0.0' # This is needed for Vagrant album_repo = Songify::AlbumRepo.new +song_repo = Songify::SongRepo.new get '/' do @albums = album_repo.get_all_albums @@ -18,3 +20,11 @@ redirect to('/') end +get '/albums/:id' do + album_id = params[:id] + @album = album_repo.find_album({id: album_id}).first + @songs = song_repo.find_songs({album_id: album_id}) + binding.pry + erb :album +end + diff --git a/songify.rb b/songify.rb index 41760d71..8738a398 100644 --- a/songify.rb +++ b/songify.rb @@ -2,9 +2,9 @@ module Songify end # require all lib/ entities and repos files here -require_relative 'lib/entity/artist.rb' require_relative 'lib/entity/album.rb' +require_relative 'lib/entity/song.rb' require_relative 'lib/repo/repo.rb' -require_relative 'lib/repo/artist_repo.rb' -require_relative 'lib/repo/album_repo.rb' \ No newline at end of file +require_relative 'lib/repo/album_repo.rb' +require_relative 'lib/repo/song_repo.rb' \ No newline at end of file diff --git a/spec/entity/artist_spec.rb b/spec/entity/artist_spec.rb deleted file mode 100644 index 4e52f067..00000000 --- a/spec/entity/artist_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative '../../spec_helper.rb' - -describe 'the artist class' do - - before(:each) do - @artist = Songify::Artist.new({'name'=> 'Seal'}) - end - - it 'should have a name' do - expect(@artist.name).to eq('Seal') - end - -end \ No newline at end of file diff --git a/spec/entity/song_spec.rb b/spec/entity/song_spec.rb new file mode 100644 index 00000000..db95ae9b --- /dev/null +++ b/spec/entity/song_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../spec_helper.rb' + +describe 'Song' do + let(:album_repo){Songify::AlbumRepo.new} + before(:each) do + album_repo.add_new_album( + {title: 'Darkness on the Edge of Town', + artist: 'Bruce Springsteen', + cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' + }) + end + it 'has a name and an album id' do + result = Songify::Song.new({name: 'Prove It All Night', album_id: 1}) + expect(result.name).to eq('Prove It All Night') + expect(result.album_id).to eq(1) + end + + it 'has an embed link' do + result = Songify::Song.new({name: 'Streets of Fire', album_id: 1, embed: "https://embed.spotify.com/?uri=spotify:track:1PuHLoIL9LTev7T5ONv5zI"}) + expect(result.embed).to eq("https://embed.spotify.com/?uri=spotify:track:1PuHLoIL9LTev7T5ONv5zI") + end +end \ No newline at end of file diff --git a/spec/repo/artist_repo_spec.rb b/spec/repo/artist_repo_spec.rb deleted file mode 100644 index 84aa1c10..00000000 --- a/spec/repo/artist_repo_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -require_relative '../../spec_helper.rb' - -describe 'the artist repo' do - let(:artist_repo) { - Songify::ArtistRepo.new - } - before(:each) do - artist_repo.drop_table - artist_repo.create_table - end - - describe 'adding' do - it 'can add an artist to the database' do - result = artist_repo.add_new_artist({name: 'Willie Nelson'}) - artists = artist_repo.get_all - expect(result.name).to eq('Willie Nelson') - expect(artists.length).to eq(1) - end - end - - describe 'finding' do - before(:each) do - artist_repo.add_new_artist({name: 'Willie Nelson'}) - artist_repo.add_new_artist({name: 'Johnny Cash'}) - end - - it 'can find an artist by name' do - result = artist_repo.find_artist_by_name({name: 'Johnny Cash'}) - expect(result.name).to eq('Johnny Cash') - expect(result.id).to eq(2) - end - - xit 'can find an artist by id' do - end - - xit 'can find all artists' do - end - end - - describe 'editing' do - it 'can edit an artist' do - artist_repo.add_new_artist({name: 'Johnny Cash'}) - result = artist_repo.update_artist({id: 1, name: "John Cash"}) - expect(result.id).to eq(1) - expect(result.name).to eq("John Cash") - end - end - - - describe 'delete' do - before(:each) do - artist_repo.add_new_artist({name: 'Willie Nelson'}) - artist_repo.add_new_artist({name: 'Johnny Cash'}) - end - - it 'can delete an artist from the database using id' do - artist_repo.delete_artist({id: 1}) - artists = artist_repo.get_all - expect(artists.length).to eq(1) - end - end - -end \ No newline at end of file diff --git a/spec/repo/song_repo_spec.rb b/spec/repo/song_repo_spec.rb new file mode 100644 index 00000000..817f51d9 --- /dev/null +++ b/spec/repo/song_repo_spec.rb @@ -0,0 +1,95 @@ +require_relative '../../spec_helper.rb' + +describe 'the song repo' do + let(:album_repo){ + Songify::AlbumRepo.new + } + let(:song_repo){ + Songify::SongRepo.new + } + before(:each){ + album_repo.drop_table + album_repo.create_table + song_repo.drop_table + song_repo.create_table + album_repo.add_new_album( + {title: 'Darkness on the Edge of Town', + artist: 'Bruce Springsteen', + cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' + }) + } + describe 'add new song' do + it 'should be able to add a song associated with a table' do + result = song_repo.add_new_song({name: 'Prove It All Night', album_id: 1, embed:'http://hello.world'}) + songs = song_repo.get_all_songs + expect(result.name).to eq('Prove It All Night') + expect(result.album_id).to eq(1) + expect(result.embed).to eq('http://hello.world') + expect(songs.length).to eq(1) + end + end + + describe 'read, update, delete' do + before(:each) do + album_repo.add_new_album( + {title: 'Pet Sounds', + artist: 'The Beach Boys', + cover: 'http://upload.wikimedia.org/wikipedia/en/b/bb/PetSoundsCover.jpg' + }) + song_repo.add_new_song( + {name: 'Sloop John B', + album_id: 2 + }) + song_repo.add_new_song( + {name: 'Something in the Night', + album_id: 1 + }) + end + it 'can get all songs' do + songs = song_repo.get_all_songs + expect(songs.length).to eq(2) + expect(songs[0].name).to eq('Sloop John B') + expect(songs[1].name).to eq('Something in the Night') + end + + it 'can find a song by id' do + result = song_repo.find_songs({id: 1}) + expect(result.first.name).to eq('Sloop John B') + end + + it 'can find a song by name' do + result = song_repo.find_songs({name: 'Something in the Night'}) + expect(result.first.album_id).to eq(1) + end + + it 'can find multiple songs of the same name' do + song_repo.add_new_song({name: 'Sloop John B', album_id: 1}) + result = song_repo.find_songs({name: 'Sloop John B'}) + expect(result[0].album_id).to eq(2) + expect(result[1].album_id).to eq(1) + end + + it 'can find all songs from an album' do + song_repo.add_new_song({name: 'Prove It All Night', album_id: 1}) + result = song_repo.find_songs({album_id: 1}) + expect(result.length).to eq(2) + expect(result[0].name).to eq('Something in the Night') + expect(result[1].name).to eq('Prove It All Night') + end + + it 'can update a song' do + result = song_repo.update_song({id: 1, album_id: 1, name: 'Sloop John B'}) + album = song_repo.find_songs({album_id: 1}) + expect(album.length).to eq(2) + expect(result.id).to eq(1) + expect(result.name).to eq('Sloop John B') + end + + it 'can delete a song' do + result = song_repo.delete_song({id: 1}) + songs = song_repo.get_all_songs + expect(songs.length).to eq(1) + expect(result.name).to eq('Sloop John B') + end + end +end \ No newline at end of file diff --git a/views/album.erb b/views/album.erb new file mode 100644 index 00000000..c3a80842 --- /dev/null +++ b/views/album.erb @@ -0,0 +1,24 @@ +
+
+
+
+ + + + + Cover URL + + +
+
+
+ <% @songs.each do |song| %> +
+
<%= song.name %>
+
+ +
+
+ <% end %> +
\ No newline at end of file diff --git a/views/index.erb b/views/index.erb index 22101564..12da08df 100644 --- a/views/index.erb +++ b/views/index.erb @@ -1,14 +1,16 @@
-
- - - - - - - -
+
+
+ + + + + + + +
+
<% @albums.each do |album| %>
From f079be53cb9e3ff2bf4b59d7724b56a6b4a2fc3d Mon Sep 17 00:00:00 2001 From: Daniel Olasky Date: Mon, 15 Dec 2014 21:16:41 -0800 Subject: [PATCH 9/9] join table --- Rakefile | 125 +++++++++++++++++++++++++------- lib/entity/playlist.rb | 9 +++ lib/repo/playlist_repo.rb | 92 +++++++++++++++++++++++ lib/repo/song_repo.rb | 13 +++- public/css/main.css | 1 + server.rb | 45 +++++++++++- songify.rb | 4 +- spec/entity/playlist_spec.rb | 10 +++ spec/repo/playlist_repo_spec.rb | 101 ++++++++++++++++++++++++++ spec/repo/song_repo_spec.rb | 5 +- views/album.erb | 27 +++++-- views/index.erb | 8 +- views/layout.erb | 2 +- views/song.erb | 14 ++++ 14 files changed, 412 insertions(+), 44 deletions(-) create mode 100644 lib/entity/playlist.rb create mode 100644 lib/repo/playlist_repo.rb create mode 100644 spec/entity/playlist_spec.rb create mode 100644 spec/repo/playlist_repo_spec.rb create mode 100644 views/song.erb diff --git a/Rakefile b/Rakefile index ca46b5e8..945e0635 100644 --- a/Rakefile +++ b/Rakefile @@ -15,29 +15,104 @@ task :seed do artist: 'Bruce Springsteen', cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' }) - puts 'seeding bruce' - @album_repo.add_new_album( - {title: 'Pet Sounds', - artist: 'The Beach Boys', - cover: 'http://upload.wikimedia.org/wikipedia/en/b/bb/PetSoundsCover.jpg' - }) - puts 'seeding the beach boys' - @album_repo.add_new_album( - {title: 'Run The Jewels 2', - artist: 'Killer Mike & El P', - cover: 'http://36.media.tumblr.com/4d1d4fa86923323f2686e9f8baacfd23/tumblr_ngbryfp3IH1t00btlo1_1280.jpg' - }) - puts 'seeding RTJ2' - @album_repo.add_new_album( - {title: 'Quality Street', - artist: 'Nick Lowe', - cover: 'http://ecx.images-amazon.com/images/I/91ZdT8CmwiL._SX425_.jpg' - }) - puts 'seeding chrimbo' - @album_repo.add_new_album({ - title: 'Summerteeth', - artist: 'Wilco', - cover: 'http://ecx.images-amazon.com/images/I/51bJzaovu7L.jpg' - }) - puts 'seeding Wilco' + @song_repo.add_new_song({ + name: 'Prove It All Night', + album_id: 1, + embed: "spotify:track:0Ye9OGxiHF3jylblTCuX7Q" + }) + @song_repo.add_new_song({ + name: "Streets Of FIre", + album_id: 1, + embed: "spotify:track:1PuHLoIL9LTev7T5ONv5zI" + }) + @song_repo.add_new_song({ + name: "Badlands", + album_id: 1, + embed: "spotify:track:0M1YQiRGel1tTMjA3orfRd" + }) + puts 'seeded bruce' + @album_repo.add_new_album( + {title: 'Pet Sounds', + artist: 'The Beach Boys', + cover: 'http://upload.wikimedia.org/wikipedia/en/b/bb/PetSoundsCover.jpg' + }) + @song_repo.add_new_song({ + name: 'Sloop John B', + album_id: 2, + embed: "spotify:track:2ULL3VZf4WwBKO4vjwT7Bg" + }) + @song_repo.add_new_song({ + name: 'God Only Knows', + album_id: 2, + embed: "spotify:track:6iGU74CwXuT4XVepjc9Emf" + }) + @song_repo.add_new_song({ + name: "Hang On To Your Ego", + album_id: 2, + embed: "spotify:track:4ZSBGLE9j9buk6DXVSryBI" + }) + puts 'seeded the beach boys' + @album_repo.add_new_album( + {title: 'Run The Jewels 2', + artist: 'Killer Mike & El P', + cover: 'http://36.media.tumblr.com/4d1d4fa86923323f2686e9f8baacfd23/tumblr_ngbryfp3IH1t00btlo1_1280.jpg' + }) + @song_repo.add_new_song({ + name: "Blockbuster Night Part 1", + album_id: 3, + embed: "spotify:track:2KxIMZDazuXN3yvPC6Kqwn" + }) + @song_repo.add_new_song({ + name: "Crown", + album_id: 3, + embed: "spotify:track:43ZfXZ1rtlnIuhfwePQUwU" + }) + @song_repo.add_new_song({ + name: "Lie, Cheat, Steal", + album_id: 3, + embed: "spotify:track:3UN6UkL6M0l8vfZS7OffZ6" + }) + puts 'seeded RTJ2' + @album_repo.add_new_album( + {title: 'Quality Street', + artist: 'Nick Lowe', + cover: 'http://ecx.images-amazon.com/images/I/91ZdT8CmwiL._SX425_.jpg' + }) + @song_repo.add_new_song({ + name: "Christmas At The Airport", + album_id: 4, + embed: "spotify:track:2bcAQKVDXBSp8NJumciMlC" + }) + @song_repo.add_new_song({ + name: "Old Toy Trains", + album_id: 4, + embed: "spotify:track:6XewVgajWGBcCYZ3LRM1Vu" + }) + @song_repo.add_new_song({ + name: "I Wish It Could Be Christmas Every Day", + album_id: 4, + embed: "spotify:track:4Evc12lXqVVcyb5XzMVUpa" + }) + puts 'seeded Quality Street' + @album_repo.add_new_album({ + title: 'Summerteeth', + artist: 'Wilco', + cover: 'http://ecx.images-amazon.com/images/I/51bJzaovu7L.jpg' + }) + @song_repo.add_new_song({ + name: "How To Fight Loneliness", + album_id: 5, + embed: "spotify:track:1CsMuJeMzRqNgS7G0fo1Gv" + }) + @song_repo.add_new_song({ + name: "Via Chicago", + album_id: 5, + embed: "spotify:track:58nPDufBVhMa2bT8G59CzS" + }) + @song_repo.add_new_song({ + name: "When you Wake Up Feeling Old", + album_id: 5, + embed: "spotify:track:2cc0vgUmSTfWCIxfmdD2uS" + }) + puts 'seeded Wilco' end \ No newline at end of file diff --git a/lib/entity/playlist.rb b/lib/entity/playlist.rb new file mode 100644 index 00000000..d8792431 --- /dev/null +++ b/lib/entity/playlist.rb @@ -0,0 +1,9 @@ +class Songify::Playlist + + attr_reader :id, :title + + def initialize(params) + @id = params[:id].to_i + @title = params[:title] + end +end \ No newline at end of file diff --git a/lib/repo/playlist_repo.rb b/lib/repo/playlist_repo.rb new file mode 100644 index 00000000..9cf23cd7 --- /dev/null +++ b/lib/repo/playlist_repo.rb @@ -0,0 +1,92 @@ +class Songify::PlaylistRepo < Songify::Repo + + def create_table + command = <<-SQL + CREATE TABLE IF NOT EXISTS playlists( + id SERIAL PRIMARY KEY, + title text + ); + SQL + @db.exec(command) + end + + def drop_table + command = <<-SQL + DROP TABLE IF EXISTS playlists CASCADE; + SQL + @db.exec(command) + end + + def create_join + command = <<-SQL + CREATE TABLE IF NOT EXISTS song_playlists( + id SERIAL PRIMARY KEY, + song_id INTEGER REFERENCES songs (id), + playlist_id INTEGER REFERENCES playlists(id) + ); + SQL + @db.exec(command) + end + + def drop_join + command = <<-SQL + DROP TABLE IF EXISTS song_playlists CASCADE; + SQL + @db.exec(command) + end + + def add_new_playlist(params) + command = <<-SQL + INSERT INTO playlists + (title) + VALUES ('#{params[:title]}') + RETURNING *; + SQL + result = @db.exec(command).first + build_playlist(result) + end + + def build_playlist(params) + Songify::Playlist.new(Hash[params.map{|k,v| [k.to_sym, v]}]) + end + + def find_playlist(params) + col = params.keys.first + val = params[col] + query = <<-SQL + SELECT * FROM playlists + WHERE #{col} = '#{val}' + SQL + result = @db.exec(query).to_a + result.map{|playlist| build_playlist(playlist)} + end + + def get_all_playlists + query = <<-SQL + SELECT * FROM playlists; + SQL + result = @db.exec(query).to_a + result.map{|playlist| build_playlist(playlist)} + end + + def add_song_to_playlist(params) + command = <<-SQL + INSERT INTO song_playlists (playlist_id, song_id) + VALUES (#{params[:playlist_id]}, #{params[:song_id]}) + RETURNING *; + SQL + result = @db.exec(command).first + find_playlist({id: result['playlist_id']}) + end + + def get_playlists_for_songs(params) + query = <<-SQL + SELECT * FROM song_playlists, songs, playlists + WHERE song_playlists.song_id = #{params[:song_id]} AND playlists.id = song_playlists.playlist_id + SQL + result = @db.exec(query).to_a + result.map{|playlist| build_playlist(playlist)} + end + + +end \ No newline at end of file diff --git a/lib/repo/song_repo.rb b/lib/repo/song_repo.rb index 9408d357..fa3a962c 100644 --- a/lib/repo/song_repo.rb +++ b/lib/repo/song_repo.rb @@ -7,7 +7,7 @@ def create_table id SERIAL PRIMARY KEY, name TEXT, embed TEXT, - album_id INTEGER REFERENCES albums (id) + album_id INTEGER REFERENCES albums (id) ON DELETE CASCADE ); SQL @db.exec(command) @@ -57,7 +57,7 @@ def find_songs(params) def update_song(params) command = <<-SQL UPDATE songs - SET (name, album_id, embed) = ('#{params[:name]}', #{params[:album_id]}, '#{params[:embed]}') + SET (name, embed, album_id) = ('#{params[:name]}', '#{params[:embed]}', #{params[:album_id]}) WHERE id = #{params[:id]} RETURNING *; SQL @@ -75,4 +75,13 @@ def delete_song(params) build_song(result) end + def get_songs_in_playlist(params) + query = <<-SQL + SELECT * FROM song_playlists, songs, playlists + WHERE song_playlists.playlist_id = #{params[:playlist_id]} AND songs.id = song_playlists.song_id + SQL + result = @db.exec(query) + result.map{|song| build_song(song)} + end + end \ No newline at end of file diff --git a/public/css/main.css b/public/css/main.css index 6bcbee0f..41e2338e 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -2,6 +2,7 @@ a { text-decoration: none; color: black; } + .album-wrapper { text-align: center; letter-spacing: 0; diff --git a/server.rb b/server.rb index 4464e713..c15e8f49 100644 --- a/server.rb +++ b/server.rb @@ -20,11 +20,52 @@ redirect to('/') end +get '/albums/:album_id/songs/:id' do + album_id = params[:album_id] + song_id = params[:id] + @album = album_repo.find_album({id: album_id}).first + @songs = song_repo.find_songs({album_id: album_id}) + @song = song_repo.find_songs({id: song_id}).first + erb :album, :layout => :layout do + erb :song + end +end + +put '/albums/:album_id/songs/:id' do + new_album = album_repo.find_album({title: params[:album]}).first + song_repo.update_song({ + id: params[:id], + name: params[:name], + album_id: new_album.id, + embed: params[:embed] + }) + redirect back +end + +delete '/albums/:album_id/songs/:id' do + @song = song_repo.delete_song({id: params[:id]}) + redirect back +end + get '/albums/:id' do album_id = params[:id] @album = album_repo.find_album({id: album_id}).first @songs = song_repo.find_songs({album_id: album_id}) - binding.pry - erb :album + erb :album, :layout => :layout +end + +delete '/albums/:id' do + @album = album_repo.delete_album({id: params[:id]}) + redirect('/') +end + +put '/albums/:id' do + @album = album_repo.update_album( + {id: params[:id], + title: params[:title], + artist: params[:artist], + cover: params[:cover] + }) + redirect to('/') end diff --git a/songify.rb b/songify.rb index 8738a398..4fd15ae5 100644 --- a/songify.rb +++ b/songify.rb @@ -4,7 +4,9 @@ module Songify # require all lib/ entities and repos files here require_relative 'lib/entity/album.rb' require_relative 'lib/entity/song.rb' +require_relative 'lib/entity/playlist.rb' require_relative 'lib/repo/repo.rb' require_relative 'lib/repo/album_repo.rb' -require_relative 'lib/repo/song_repo.rb' \ No newline at end of file +require_relative 'lib/repo/song_repo.rb' +require_relative 'lib/repo/playlist_repo.rb' \ No newline at end of file diff --git a/spec/entity/playlist_spec.rb b/spec/entity/playlist_spec.rb new file mode 100644 index 00000000..3f1eb5e4 --- /dev/null +++ b/spec/entity/playlist_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../spec_helper.rb' + +describe 'playlist' do + let(:playlist){Songify::Playlist.new({id: 1, title: "My Chill Playlist"})} + + it 'has an id and a title' do + expect(playlist.id).to eq(1) + expect(playlist.title).to eq("My Chill Playlist") + end +end \ No newline at end of file diff --git a/spec/repo/playlist_repo_spec.rb b/spec/repo/playlist_repo_spec.rb new file mode 100644 index 00000000..f29b3b75 --- /dev/null +++ b/spec/repo/playlist_repo_spec.rb @@ -0,0 +1,101 @@ +require_relative '../../spec_helper.rb' + +describe 'the playlist repo' do + let(:playlist_repo){ + Songify::PlaylistRepo.new + } + let(:song_repo){ + Songify::SongRepo.new + } + let(:album_repo){ + Songify::AlbumRepo.new + } + before(:each){ + album_repo.drop_table + album_repo.create_table + song_repo.drop_table + song_repo.create_table + playlist_repo.drop_table + playlist_repo.create_table + playlist_repo.drop_join + playlist_repo.create_join + album_repo.add_new_album( + {title: 'Darkness on the Edge of Town', + artist: 'Bruce Springsteen', + cover: 'http://upload.wikimedia.org/wikipedia/en/a/af/BruceSpringsteenDarknessontheEdgeofTown.jpg' + }) + song_repo.add_new_song({name: 'Prove It All Night', album_id: 1, embed:'http://hello.world'}) + song_repo.add_new_song({name: 'Song 2', album_id: 1, embed:"another.html"}) + song_repo.add_new_song({name: 'third song', album_id: 1, embed:"more embed"}) + } + + describe 'add new playlist' do + it 'can create a playlist' do + result = playlist_repo.add_new_playlist({title: 'My Sweet Playlist'}) + expect(result.id).to eq(1) + playlists = playlist_repo.get_all_playlists + expect(playlists.length).to eq(1) + end + end + + describe 'read,edit,delete' do + + before(:each){ + playlist_repo.add_new_playlist({title: "My chillass playlist"}) + } + it 'can find a playlist' do + result = playlist_repo.find_playlist({id: 1}) + expect(result.first.title).to eq("My chillass playlist") + end + + it 'can get all playlists' do + playlist_repo.add_new_playlist({title: "My second playlist"}) + result = playlist_repo.get_all_playlists + expect(result.length).to eq(2) + end + + it 'can add a song to two different playlists' do + playlist_repo.add_new_playlist({title: "Second sweet playlist"}) + playlist_repo.add_song_to_playlist({song_id: 1, playlist_id: 1}) + playlist_repo.add_song_to_playlist({song_id: 1, playlist_id: 2}) + one = song_repo.get_songs_in_playlist({playlist_id: 1}) + two = song_repo.get_songs_in_playlist({playlist_id: 2}) + expect(one.first.name).to eq('Prove It All Night') + expect(two.first.name).to eq('Prove It All Night') + end + + it 'can get all the playlists a song appears on' do + playlist_repo.add_new_playlist({title: "Second playlist"}) + playlist_repo.add_song_to_playlist({song_id: 1, playlist_id: 1}) + playlist_repo.add_song_to_playlist({song_id: 1, playlist_id: 2}) + result = playlist_repo.get_playlists_for_songs({song_id: 1}) + expect(result.length).to eq(2) + expect(result.first.title).to eq('My chillass playlist') + expect(result[1].title).to eq('Second playlist') + end + + describe 'edit/update' do + it 'can update the name of a playlist' do + result = playlist_repo.update_playlist({id: 1, title: 'edited'}) + expect(result.title).to eq('edited') + end + + describe 'delete' do + it 'can delete a playlist' do + playlist_repo.add_new_playlist({title: "Second playlist"}) + playlist_repo.delete_playlist({id: 1}) + expect(playlist_repo.get_all_playlists.length).to eq(1) + end + + it 'can delete a join' do + playlist_repo.add_song_to_playlist({song_id: 1, playlist_id: 1}) + playlist_repo.add_song_to_playlist({song_id: 2, playlist_id: 1}) + playlist_repo.delete_join({song_id: 1, playlist_id: 1}) + result = song_repo.get_songs_in_playlist({playlist_id: 1}) + expect(result.length).to eq(1) + end + end + end + + end +end \ No newline at end of file diff --git a/spec/repo/song_repo_spec.rb b/spec/repo/song_repo_spec.rb index 817f51d9..3c5ebc38 100644 --- a/spec/repo/song_repo_spec.rb +++ b/spec/repo/song_repo_spec.rb @@ -78,11 +78,11 @@ end it 'can update a song' do - result = song_repo.update_song({id: 1, album_id: 1, name: 'Sloop John B'}) + result = song_repo.update_song({id: 1, album_id: 1, name: 'Sloop John'}) album = song_repo.find_songs({album_id: 1}) expect(album.length).to eq(2) expect(result.id).to eq(1) - expect(result.name).to eq('Sloop John B') + expect(result.name).to eq('Sloop John') end it 'can delete a song' do @@ -91,5 +91,6 @@ expect(songs.length).to eq(1) expect(result.name).to eq('Sloop John B') end + end end \ No newline at end of file diff --git a/views/album.erb b/views/album.erb index c3a80842..9b828d57 100644 --- a/views/album.erb +++ b/views/album.erb @@ -1,24 +1,37 @@
-
+ - + - Cover URL - +
+
+
+ + +
+
+
<% @songs.each do |song| %> -
-
<%= song.name %>
+ +
<%= song.name %>
+
- +
+ <% end %>
+
+ <% if @song %> + <%= yield %> <% end %> +
\ No newline at end of file diff --git a/views/index.erb b/views/index.erb index 12da08df..1eb6f1b8 100644 --- a/views/index.erb +++ b/views/index.erb @@ -3,12 +3,12 @@
- + - + - - + +
diff --git a/views/layout.erb b/views/layout.erb index cb4287df..6c744924 100644 --- a/views/layout.erb +++ b/views/layout.erb @@ -3,7 +3,7 @@ Codestin Search App - + diff --git a/views/song.erb b/views/song.erb new file mode 100644 index 00000000..5c0ac851 --- /dev/null +++ b/views/song.erb @@ -0,0 +1,14 @@ +
+ + + + + + + + +
+
+ + +
\ No newline at end of file