diff --git a/.gitignore b/.gitignore index 050c9d95c7..2eb6f54617 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ /log/* !/log/.keep /tmp + +coverage diff --git a/.rspec b/.rspec new file mode 100644 index 0000000000..83e16f8044 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/Gemfile b/Gemfile index 69890fc981..922f613846 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '4.2.5' # Use sqlite3 as the database for Active Record - +gem 'bootstrap-sass', '~> 3.3.6' gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' @@ -33,6 +33,11 @@ gem 'sdoc', '~> 0.4.0', group: :doc group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' + gem 'rspec-rails' +end + +group :test do + gem 'simplecov', require: false end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index dee2f0686a..801083d137 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -37,12 +37,18 @@ GEM thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) arel (6.0.3) + autoprefixer-rails (6.1.2) + execjs + json better_errors (2.1.1) coderay (>= 1.0.0) erubis (>= 2.6.6) rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) + bootstrap-sass (3.3.6) + autoprefixer-rails (>= 5.2.1) + sass (>= 3.3.4) builder (3.2.2) byebug (8.2.1) choice (0.2.0) @@ -55,6 +61,8 @@ GEM execjs coffee-script-source (1.10.0) debug_inspector (0.0.2) + diff-lcs (1.2.5) + docile (1.1.5) erubis (2.7.0) execjs (2.6.0) globalid (0.3.6) @@ -120,6 +128,23 @@ GEM thor (>= 0.18.1, < 2.0) rake (10.4.2) rdoc (4.2.0) + rspec-core (3.4.1) + rspec-support (~> 3.4.0) + rspec-expectations (3.4.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-mocks (3.4.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.4.0) + rspec-rails (3.4.0) + actionpack (>= 3.0, < 4.3) + activesupport (>= 3.0, < 4.3) + railties (>= 3.0, < 4.3) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-support (~> 3.4.0) + rspec-support (3.4.1) ruby-graphviz (1.2.2) sass (3.4.19) sass-rails (5.0.4) @@ -131,6 +156,11 @@ GEM sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) + simplecov (0.11.0) + docile (~> 1.1.0) + json (~> 1.8) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) slop (3.6.0) spring (1.5.0) sprockets (3.4.1) @@ -162,6 +192,7 @@ PLATFORMS DEPENDENCIES better_errors binding_of_caller + bootstrap-sass (~> 3.3.6) byebug coffee-rails (~> 4.1.0) jbuilder (~> 2.0) @@ -170,8 +201,10 @@ DEPENDENCIES pry-rails rails (= 4.2.5) rails-erd + rspec-rails sass-rails (~> 5.0) sdoc (~> 0.4.0) + simplecov spring sqlite3 turbolinks diff --git a/app/assets/images/owl.jpg b/app/assets/images/owl.jpg new file mode 100644 index 0000000000..b3ded30950 Binary files /dev/null and b/app/assets/images/owl.jpg differ diff --git a/app/assets/javascripts/album.coffee b/app/assets/javascripts/album.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/album.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e07c5a830f..f91cae5d9b 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,6 +11,7 @@ // about supported directives. // //= require jquery +//= require bootstrap-sprockets //= require jquery_ujs //= require turbolinks //= require_tree . diff --git a/app/assets/javascripts/books.coffee b/app/assets/javascripts/books.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/books.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/home.coffee b/app/assets/javascripts/home.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/home.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/movies.coffee b/app/assets/javascripts/movies.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/movies.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/album.scss b/app/assets/stylesheets/album.scss new file mode 100644 index 0000000000..2bb51d310f --- /dev/null +++ b/app/assets/stylesheets/album.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the album controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.scss similarity index 73% rename from app/assets/stylesheets/application.css rename to app/assets/stylesheets/application.scss index f9cd5b3483..f6a8e870fa 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.scss @@ -10,6 +10,20 @@ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * - *= require_tree . - *= require_self */ + +@import "bootstrap-sprockets"; +@import "bootstrap"; + +.page-header { + background-image: image-url("owl.jpg"); + background-repeat: no-repeat; +} + +.page-header h1 { + margin-left: 150px; +} + +form .btn-primary { + margin-bottom: 10px; +} diff --git a/app/assets/stylesheets/books.scss b/app/assets/stylesheets/books.scss new file mode 100644 index 0000000000..81379d103f --- /dev/null +++ b/app/assets/stylesheets/books.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the books controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss new file mode 100644 index 0000000000..f0ddc6846a --- /dev/null +++ b/app/assets/stylesheets/home.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the home controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/movies.scss b/app/assets/stylesheets/movies.scss new file mode 100644 index 0000000000..70aaa8a9a4 --- /dev/null +++ b/app/assets/stylesheets/movies.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the movies controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/albums_controller.rb b/app/controllers/albums_controller.rb new file mode 100644 index 0000000000..957c2c1dfd --- /dev/null +++ b/app/controllers/albums_controller.rb @@ -0,0 +1,56 @@ +class AlbumsController < ApplicationController + + def index + @albums = Album.all.sort_by { |album| -album.rank } + end + + def upvote + album = Album.find(params[:id]) + album.rank += 1 + album.save + redirect_to album_path(album) + end + + def new + @album = Album.new + end + + def create + @album = Album.new(album_params[:album]) + if @album.save + redirect_to album_path(@album) + else + render "new" + end + end + + def show + @album = Album.find(params[:id]) + end + + def edit + @album = Album.find(params[:id]) + end + + def update + @album = Album.find(params[:id]) + @album.update( album_params[:album]) + if @album.save + redirect_to album_path(@album) + else + render "edit" + end + end + + def destroy + Album.destroy(params[:id]) + redirect_to albums_path + end + + private + + def album_params + params.permit(album:[:name, :artist, :description, :rank]) + end + +end diff --git a/app/controllers/books_controller.rb b/app/controllers/books_controller.rb new file mode 100644 index 0000000000..a88afb2766 --- /dev/null +++ b/app/controllers/books_controller.rb @@ -0,0 +1,57 @@ +class BooksController < ApplicationController + + def index + @books = Book.all.sort_by { |book| -book.rank } + end + + def upvote + book = Book.find(params[:id]) + book.rank += 1 + book.save + redirect_to book_path(book) + end + + def new + @book = Book.new + end + + def create + @book = Book.new(book_params) + if @book.save + redirect_to book_path(@book) + else + render "new" + end + end + + def show + @book = Book.find(params[:id]) + end + + def edit + @book = Book.find(params[:id]) + end + + def update + @book = Book.find(params[:id]) + @book.update( book_params ) + if @book.save + redirect_to book_path(@book) + else + render "edit" + end + end + + def destroy + Book.destroy(params[:id]) + redirect_to books_path + end + + private + + def book_params + params.require(:book).permit(:name, :author, :description, :rank) + end + + +end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb new file mode 100644 index 0000000000..6170b646cf --- /dev/null +++ b/app/controllers/home_controller.rb @@ -0,0 +1,8 @@ +class HomeController < ApplicationController + + def index + @movies = Movie.all.sort_by { |movie| -movie.rank }.first(10) + @albums = Album.all.sort_by { |album| -album.rank }.first(10) + @books = Book.all.sort_by { |book| -book.rank }.first(10) + end +end diff --git a/app/controllers/movies_controller.rb b/app/controllers/movies_controller.rb new file mode 100644 index 0000000000..9774b91bb4 --- /dev/null +++ b/app/controllers/movies_controller.rb @@ -0,0 +1,57 @@ +class MoviesController < ApplicationController + + def index + @movies = Movie.all.sort_by { |movie| -movie.rank } + end + + def new + @movie = Movie.new + end + + def create + @movie = Movie.new(movie_params[:movie]) + if @movie.save + redirect_to movie_path(@movie) + else + render "new" + end + end + + def show + @movie = Movie.find(params[:id]) + end + + def edit + @movie = Movie.find(params[:id]) + end + + def update + @movie = Movie.find(params[:id]) + @movie.update( movie_params[:movie]) + if @movie.save + redirect_to movie_path(@movie) + else + render "edit" + end + end + + def destroy + Movie.destroy(params[:id]) + redirect_to movies_path + end + + def upvote + movie = Movie.find(params[:id]) + movie.rank += 1 + movie.save + redirect_to movie_path(movie) + end + + private + + def movie_params + params.permit(movie:[:name, :director, :description, :rank]) + end + + +end diff --git a/app/helpers/album_helper.rb b/app/helpers/album_helper.rb new file mode 100644 index 0000000000..23ace66827 --- /dev/null +++ b/app/helpers/album_helper.rb @@ -0,0 +1,2 @@ +module AlbumHelper +end diff --git a/app/helpers/books_helper.rb b/app/helpers/books_helper.rb new file mode 100644 index 0000000000..4b9311e0be --- /dev/null +++ b/app/helpers/books_helper.rb @@ -0,0 +1,2 @@ +module BooksHelper +end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb new file mode 100644 index 0000000000..23de56ac60 --- /dev/null +++ b/app/helpers/home_helper.rb @@ -0,0 +1,2 @@ +module HomeHelper +end diff --git a/app/helpers/movies_helper.rb b/app/helpers/movies_helper.rb new file mode 100644 index 0000000000..493eee555f --- /dev/null +++ b/app/helpers/movies_helper.rb @@ -0,0 +1,2 @@ +module MoviesHelper +end diff --git a/app/models/album.rb b/app/models/album.rb new file mode 100644 index 0000000000..cbbf38bde0 --- /dev/null +++ b/app/models/album.rb @@ -0,0 +1,6 @@ +class Album < ActiveRecord::Base + validates :name, presence: true, length: { maximum: 100 } + validates :description, length: {maximum: 500 } + validates :artist, length: {maximum: 100 } + +end diff --git a/app/models/book.rb b/app/models/book.rb new file mode 100644 index 0000000000..c72e044a92 --- /dev/null +++ b/app/models/book.rb @@ -0,0 +1,6 @@ +class Book < ActiveRecord::Base + validates :name, presence: true, length: { maximum: 100 } + validates :description, length: {maximum: 500 } + validates :author, length: {maximum: 100 } + +end diff --git a/app/models/movie.rb b/app/models/movie.rb new file mode 100644 index 0000000000..11064ae833 --- /dev/null +++ b/app/models/movie.rb @@ -0,0 +1,6 @@ +class Movie < ActiveRecord::Base + validates :name, presence: true, length: { maximum: 100 } + validates :description, length: {maximum: 500 } + validates :director, length: {maximum: 100 } + +end diff --git a/app/views/albums/edit.html.erb b/app/views/albums/edit.html.erb new file mode 100644 index 0000000000..42c50caa33 --- /dev/null +++ b/app/views/albums/edit.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/form', + locals:{ medium: @album, action: :update, title: "Edit Album", creator: :artist, rank_value: @album.rank} %> diff --git a/app/views/albums/index.html.erb b/app/views/albums/index.html.erb new file mode 100644 index 0000000000..d65c78cecd --- /dev/null +++ b/app/views/albums/index.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/index', + locals:{media:@albums, media_type: :album } %> diff --git a/app/views/albums/new.html.erb b/app/views/albums/new.html.erb new file mode 100644 index 0000000000..84f0f0a9f8 --- /dev/null +++ b/app/views/albums/new.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/form', + locals:{ medium: @album, action: :create, title: "New Album", creator: :artist, rank_value: 0} %> diff --git a/app/views/albums/show.html.erb b/app/views/albums/show.html.erb new file mode 100644 index 0000000000..41ada7c2d4 --- /dev/null +++ b/app/views/albums/show.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/detail', + locals:{ medium: @album, creator: @album.artist, byline: "Recorded by: ", media_type: :albums} %> diff --git a/app/views/books/edit.html.erb b/app/views/books/edit.html.erb new file mode 100644 index 0000000000..e52bb31153 --- /dev/null +++ b/app/views/books/edit.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/form', + locals:{ medium: @book, action: :update, title: "Edit Book", creator: :author, rank_value: @book.rank} %> diff --git a/app/views/books/index.html.erb b/app/views/books/index.html.erb new file mode 100644 index 0000000000..4ecd01613f --- /dev/null +++ b/app/views/books/index.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/index', + locals:{media:@books, media_type: :book } %> diff --git a/app/views/books/new.html.erb b/app/views/books/new.html.erb new file mode 100644 index 0000000000..a0813b365f --- /dev/null +++ b/app/views/books/new.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/form', + locals:{ medium: @book, action: :create, title: "New Book", creator: :author, rank_value: 0} %> diff --git a/app/views/books/show.html.erb b/app/views/books/show.html.erb new file mode 100644 index 0000000000..848c96905a --- /dev/null +++ b/app/views/books/show.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/detail', + locals:{ medium: @book, creator: @book.author, byline: "Written by: ", media_type: :books} %> diff --git a/app/views/home/_list.html.erb b/app/views/home/_list.html.erb new file mode 100644 index 0000000000..c8dd9da734 --- /dev/null +++ b/app/views/home/_list.html.erb @@ -0,0 +1,11 @@ +
+

Top <%= media_type.capitalize %>

+ <% media.each do |item| %> +

+ <%= link_to item.name, polymorphic_path(item) %> + Ranked: <%= item.rank %> +

+ <% end %> + + <%= link_to "View More " + media_type.to_s.capitalize, polymorphic_path(media_type) %> +
diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb new file mode 100644 index 0000000000..82224e38c2 --- /dev/null +++ b/app/views/home/index.html.erb @@ -0,0 +1,12 @@ +
+
+
+ <%= render partial:'list', + locals:{media: @movies, media_type: :movies} %> + <%= render partial:'list', + locals:{media: @books, media_type: :books} %> + <%= render partial:'list', + locals:{media: @albums, media_type: :albums} %> +
+
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 2d02e8fbd4..0adcafd4e5 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,8 +7,19 @@ <%= csrf_meta_tags %> +
+
+ +
-<%= yield %> + + <%= yield %> +
diff --git a/app/views/movies/edit.html.erb b/app/views/movies/edit.html.erb new file mode 100644 index 0000000000..79b9c659ed --- /dev/null +++ b/app/views/movies/edit.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/form', + locals:{ medium: @movie, action: :update, title: "Edit Movie", creator: :director, rank_value: @movie.rank} %> diff --git a/app/views/movies/index.html.erb b/app/views/movies/index.html.erb new file mode 100644 index 0000000000..ffd747c3b7 --- /dev/null +++ b/app/views/movies/index.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/index', + locals:{media:@movies, media_type: :movie } %> diff --git a/app/views/movies/new.html.erb b/app/views/movies/new.html.erb new file mode 100644 index 0000000000..1128469322 --- /dev/null +++ b/app/views/movies/new.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/form', + locals:{ medium: @movie, action: :create, title: "New Movie", creator: :director, rank_value: 0} %> diff --git a/app/views/movies/show.html.erb b/app/views/movies/show.html.erb new file mode 100644 index 0000000000..ffb621d9b8 --- /dev/null +++ b/app/views/movies/show.html.erb @@ -0,0 +1,2 @@ +<%= render partial:'shared/detail', + locals:{ medium: @movie, creator: @movie.director, byline: "Directed by: ", media_type: :movies} %> diff --git a/app/views/shared/_detail.html.erb b/app/views/shared/_detail.html.erb new file mode 100644 index 0000000000..1999a99e92 --- /dev/null +++ b/app/views/shared/_detail.html.erb @@ -0,0 +1,19 @@ +
+
+

<%= medium.name %> <%= byline %><%= creator %>

+

+ Ranked: <%= medium.rank %> +

+

+ <%= medium.description %> +

+
+ <%= link_to "Upvote", polymorphic_path(medium, action: :upvote ), method: :patch, class: "btn btn-primary" %> +
+ + <%= link_to "Edit #{medium.name}", edit_polymorphic_path(medium), class: "btn btn-default" %> + <%= link_to "DELETE", polymorphic_path(medium), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-danger" %> + <%= link_to "View All " + media_type.to_s.capitalize, polymorphic_path(media_type), class: "btn btn-default" %> + <%= link_to "View All Media", root_path, class: "btn btn-default" %> +
+
diff --git a/app/views/shared/_form.html.erb b/app/views/shared/_form.html.erb new file mode 100644 index 0000000000..e40916e44d --- /dev/null +++ b/app/views/shared/_form.html.erb @@ -0,0 +1,24 @@ +
+
+
+ <%= form_for medium, url:{action: action}, :html => {:class => "form" } do |f| %> +

<%= title %>

+
+ <%= f.label :name %> + <%= f.text_field :name, class: "form-control" %> +
+
+ <%= f.label creator %> + <%= f.text_field creator, class: "form-control" %> +
+
+ <%= f.label :description %>
+ <%= f.text_area :description, class: "form-control" %>
+
+ <%= f.hidden_field :rank, :value => rank_value %> + <%= f.submit "Save", class: "btn btn-default" %> + <% end %> + +
+
+
diff --git a/app/views/shared/_index.html.erb b/app/views/shared/_index.html.erb new file mode 100644 index 0000000000..53e4fd8560 --- /dev/null +++ b/app/views/shared/_index.html.erb @@ -0,0 +1,23 @@ +
+ + + + + + + + + + <% media.each do |medium| %> + + + + + + <% end %> + +
RankingNameUpvote
Ranked: <%= medium.rank %><%= link_to medium.name, polymorphic_path(medium) %><%= link_to "Upvote", polymorphic_path(medium, action: :upvote ), method: :patch, class: "btn btn-default" %>
+ + <%= link_to "View All Media", root_path, class: "btn btn-default" %> + <%= link_to "Add a #{media_type.capitalize}", new_polymorphic_path(media_type), class: "btn btn-default" %> +
diff --git a/config/routes.rb b/config/routes.rb index 3f66539d54..4169a4d12f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,15 @@ Rails.application.routes.draw do + root 'home#index' + patch 'movies/:id/upvote' => 'movies#upvote', as: :upvote_movie + patch 'albums/:id/upvote' => 'albums#upvote', as: :upvote_album + patch 'book/:id/upvote' => 'books#upvote', as: :upvote_book + + resources :movies + + resources :books + + resources :albums + # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/db/migrate/20151130213629_create_movies.rb b/db/migrate/20151130213629_create_movies.rb new file mode 100644 index 0000000000..1c40a5f879 --- /dev/null +++ b/db/migrate/20151130213629_create_movies.rb @@ -0,0 +1,12 @@ +class CreateMovies < ActiveRecord::Migration + def change + create_table :movies do |t| + t.string :name + t.string :director + t.string :description + t.integer :rank + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20151130213656_create_books.rb b/db/migrate/20151130213656_create_books.rb new file mode 100644 index 0000000000..12eb4ee8b2 --- /dev/null +++ b/db/migrate/20151130213656_create_books.rb @@ -0,0 +1,12 @@ +class CreateBooks < ActiveRecord::Migration + def change + create_table :books do |t| + t.string :name + t.string :author + t.string :description + t.integer :rank + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20151130213741_create_albums.rb b/db/migrate/20151130213741_create_albums.rb new file mode 100644 index 0000000000..9f04354899 --- /dev/null +++ b/db/migrate/20151130213741_create_albums.rb @@ -0,0 +1,12 @@ +class CreateAlbums < ActiveRecord::Migration + def change + create_table :albums do |t| + t.string :name + t.string :artist + t.string :description + t.integer :rank + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000000..e9b5473eeb --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,43 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20151130213741) do + + create_table "albums", force: :cascade do |t| + t.string "name" + t.string "artist" + t.string "description" + t.integer "rank" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "books", force: :cascade do |t| + t.string "name" + t.string "author" + t.string "description" + t.integer "rank" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "movies", force: :cascade do |t| + t.string "name" + t.string "director" + t.string "description" + t.integer "rank" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/db/seeds.rb b/db/seeds.rb index 4edb1e857e..0755115177 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,3 +5,37 @@ # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) + + +seed_movies = [ + {name:"Cats", director:"Mr. Cat", description:"A movie about cats", rank:2}, + {name:"Another Movie", director:"Hello", description:"Hi", rank:4}, + {name:"Dogs", director:"Mr.Dog", description:"Great Movie", rank:1} + +] + +seed_movies.each do |seed| + Movie.create(seed) +end + +seed_books = [ + {name:"Friends", author:"Emily", description:"A book about friends", rank:12}, + {name:"Another Book", author:"Emily", description:"Hi", rank:2}, + {name:"Cats and Dogs", author:"You", description:"Great Book", rank:1} + +] + +seed_books.each do |seed| + Book.create(seed) +end + +seed_albums = [ + {name:"Songs to Sing", artist:"Emily", description:"Good Songs", rank:2}, + {name:"Christmas Songs", artist:"Santa", description:"Songs for the Holiday", rank:23}, + {name:"Songs about Cats", artist:"You", description:"Happy Songs", rank:23} + +] + +seed_albums.each do |seed| + Album.create(seed) +end diff --git a/spec/controllers/albums_controller_spec.rb b/spec/controllers/albums_controller_spec.rb new file mode 100644 index 0000000000..728c34f4c6 --- /dev/null +++ b/spec/controllers/albums_controller_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +RSpec.describe AlbumsController, type: :controller do + it_behaves_like "a medium controller" do + let(:good_params) do + { + album:{ + name: "Songs", artist: "You", description: "A Good Album", rank: 0 + } + } + end + let(:bad_params) do + { + album:{ + artist: "Me", description: "So many good songs", rank: 0 + } + } + end + let(:media_type) do + :album + end + let(:media_type_plural) do + :albums + end + let(:test_medium) do + Album.create( name: "An album", artist: "You", description: "SONGS", rank: 0 ) + end + let(:good_update_params) do + { + id: test_medium.id, + album:{ + name: "New name", artist: "You", description: "SONGS", rank: 0 + } + } + end + + let(:bad_update_params) do + { + id: test_medium.id, + album: { name: nil, artist: "You", description: "A Good Album", rank: 0 } + } + end + end +end diff --git a/spec/controllers/books_controller_spec.rb b/spec/controllers/books_controller_spec.rb new file mode 100644 index 0000000000..ef790635d7 --- /dev/null +++ b/spec/controllers/books_controller_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +RSpec.describe BooksController, type: :controller do + it_behaves_like "a medium controller" do + let(:good_params) do + { + book:{ + name: "A Book", author: "You", description: "A Good Book", rank: 0 + } + } + end + let(:bad_params) do + { + book:{ + author: "You", description: "A Good Book", rank: 0 + } + } + end + let(:media_type) do + :book + end + let(:media_type_plural) do + :books + end + let(:test_medium) do + Book.create( name: "A Book", author: "You", description: "A Good Book", rank: 0 ) + end + let(:good_update_params) do + { + id: test_medium.id, + book:{ + name: "New name", author: "You", description: "A Good Book", rank: 0 + } + } + end + + let(:bad_update_params) do + { + id: test_medium.id, + book: { name: nil, author: "You", description: "A Good Book", rank: 0 } + } + end + end +end diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb new file mode 100644 index 0000000000..447c04c3bb --- /dev/null +++ b/spec/controllers/home_controller_spec.rb @@ -0,0 +1,12 @@ +require 'rails_helper' + +RSpec.describe HomeController, type: :controller do + + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 + end + end + +end diff --git a/spec/controllers/movies_controller_spec.rb b/spec/controllers/movies_controller_spec.rb new file mode 100644 index 0000000000..416b43d9f4 --- /dev/null +++ b/spec/controllers/movies_controller_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +RSpec.describe MoviesController, type: :controller do + it_behaves_like "a medium controller" do + let(:good_params) do + { + movie:{ + name: "Hello", director: "You", description: "A Good Movie", rank: 0 + } + } + end + let(:bad_params) do + { + movie:{ + director: "You", description: "A Good Movie", rank: 0 + } + } + end + let(:media_type) do + :movie + end + let(:media_type_plural) do + :movies + end + let(:test_medium) do + Movie.create( name: "Hello", director: "You", description: "A Good Movie", rank: 0 ) + end + let(:good_update_params) do + { + id: test_medium.id, + movie:{ + name: "New name", director: "new director", description: "A very Good Movie", rank: 0 + } + } + end + + let(:bad_update_params) do + { + id: test_medium.id, + movie: { name: nil, director: "You", description: "A Good Movie", rank: 0 } + } + end + end +end diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb new file mode 100644 index 0000000000..f480eeab4f --- /dev/null +++ b/spec/helpers/home_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the HomeHelper. For example: +# +# describe HomeHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +# RSpec.describe HomeHelper, type: :helper do +# pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/helpers/movies_helper_spec.rb b/spec/helpers/movies_helper_spec.rb new file mode 100644 index 0000000000..374e9d62b0 --- /dev/null +++ b/spec/helpers/movies_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the PostsHelper. For example: +# +# describe PostsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +# RSpec.describe MoviesHelper, type: :helper do +# # pending "add some examples to (or delete) #{__FILE__}" +# end diff --git a/spec/models/album_spec.rb b/spec/models/album_spec.rb new file mode 100644 index 0000000000..6dd2940c97 --- /dev/null +++ b/spec/models/album_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe Album, type: :model do + it_behaves_like "a medium" + + it "artist cannot have 101 characters" do + expect(Album.new(name: "a", artist: "a" * 101)).to be_invalid + end + + it "director can have 100 characters" do + expect(Album.new(name: "a", artist: "a" * 100)).to be_valid + end + +end diff --git a/spec/models/book_spec.rb b/spec/models/book_spec.rb new file mode 100644 index 0000000000..480c0bc3e6 --- /dev/null +++ b/spec/models/book_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe Book, type: :model do + it_behaves_like "a medium" + + it "author cannot have 101 characters" do + expect(Book.new(name: "a", author: "a" * 101)).to be_invalid + end + + it "director can have 100 characters" do + expect(Book.new(name: "a", author: "a" * 100)).to be_valid + end + +end diff --git a/spec/models/movie_spec.rb b/spec/models/movie_spec.rb new file mode 100644 index 0000000000..31c8b2aa16 --- /dev/null +++ b/spec/models/movie_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe Movie, type: :model do + it_behaves_like "a medium" + + it "director cannot have 101 characters" do + expect(Movie.new(name: "a", director: "a" * 101)).to be_invalid + end + + it "director can have 100 characters" do + expect(Movie.new(name: "a", director: "a" * 100)).to be_valid + end + +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000000..de00292b71 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,61 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +SimpleCov.start do + add_filter "/support/" +end + +# Checks for pending migration and applies them before tests are run. +# If you are not using ActiveRecord, you can remove this line. +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000000..c1697e0176 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,95 @@ +require 'simplecov' +SimpleCov.start 'rails' + +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # 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 + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/spec/support/medium_controller_spec.rb b/spec/support/medium_controller_spec.rb new file mode 100644 index 0000000000..3366f1d9f8 --- /dev/null +++ b/spec/support/medium_controller_spec.rb @@ -0,0 +1,104 @@ +require 'rails_helper' + +include Rails.application.routes.url_helpers + +RSpec.shared_examples "a medium controller" do + + describe "GET 'index'" do + it "is successful" do + get :index + expect(response.status).to eq 200 + end + end + + describe "GET 'new'" do + it "renders new view" do + get :new + expect(subject).to render_template :new + end + end + + describe "POST 'create'" do + before :each do + post :create, good_params + end + + it "redirects to show page" do + expect(subject).to redirect_to polymorphic_path(assigns(media_type)) + end + + it "renders new template on error" do + post :create, bad_params + expect(subject).to render_template :new + end + end + + describe "GET 'show'" do + it "renders the show view" do + get :show, id: test_medium.id + expect(subject).to render_template :show + end + end + + describe "GET 'edit'" do + it "renders edit view" do + get :edit, id: test_medium.id + expect(subject).to render_template :edit + end + end + + describe "PATCH 'update'" do + before :each do + patch :update, good_update_params + end + + it "redirects to show page" do + expect(subject).to redirect_to polymorphic_path(assigns(media_type)) + end + + it "updates the item" do + test_medium.reload + expect(test_medium.name).to eq("New name") + end + + it "renders edit template on error" do + patch :update, bad_update_params + expect(subject).to render_template :edit + end + + it "does not change the item if params are bad" do + patch :update, bad_update_params + expect(test_medium.name).not_to eql("New name") + end + end + + describe "DELETE 'destroy'" do + before :each do + delete :destroy, id: test_medium.id + end + it "redirects to the index view" do + expect(subject).to redirect_to polymorphic_path(media_type_plural) + end + end + + describe "PATCH 'upvote'" do + + let(:upvote_params) do { + id: test_medium.id + } + end + + before :each do + patch :upvote, upvote_params + end + + it "redirects to show page" do + expect(subject).to redirect_to polymorphic_path(test_medium) + end + + it "increases the rank value by 1" do + test_medium.reload + expect(test_medium.rank).to eq 1 + end + end +end diff --git a/spec/support/medium_spec.rb b/spec/support/medium_spec.rb new file mode 100644 index 0000000000..9bcfcd15af --- /dev/null +++ b/spec/support/medium_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.shared_examples "a medium" do + describe ".validates" do + it "must have a name" do + expect(described_class.new(name: nil)).to_not be_valid + end + end + + it "name cannot have 101 characters" do + expect(described_class.new(name: "a" * 101)).to be_invalid + end + + it "name can have 100 characters" do + expect(described_class.new(name: "a" * 100)).to be_valid + end + + it "description cannot have 501 characters" do + expect(described_class.new(name: "a", description: "a" * 501)).to be_invalid + end + + it "description can have 500 characters" do + expect(described_class.new(name: "a", description: "a" * 500)).to be_valid + end +end