From c1badaf695255b1327d5a2eba517ff53f8d527b1 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 18:27:00 -0800 Subject: [PATCH 01/27] update bundler (initial install) --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 16c3b7bc..97a2dd53 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -254,4 +254,4 @@ RUBY VERSION ruby 2.4.4p296 BUNDLED WITH - 1.16.2 + 2.2.11 From fb8fb0188ef92ea3f8628f961e62600fdcb1bf2e Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 18:27:12 -0800 Subject: [PATCH 02/27] add owner to dog --- app/models/dog.rb | 3 +++ app/models/user.rb | 2 ++ db/migrate/20210219021259_add_owner_to_dogs.rb | 5 +++++ db/schema.rb | 4 +++- 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20210219021259_add_owner_to_dogs.rb diff --git a/app/models/dog.rb b/app/models/dog.rb index eb40bf6e..e358e317 100644 --- a/app/models/dog.rb +++ b/app/models/dog.rb @@ -1,3 +1,6 @@ class Dog < ApplicationRecord has_many_attached :images + belongs_to :user + + alias_method :owner, :user end diff --git a/app/models/user.rb b/app/models/user.rb index b2091f9a..680f4357 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,4 +3,6 @@ class User < ApplicationRecord # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable + + has_many :dogs end diff --git a/db/migrate/20210219021259_add_owner_to_dogs.rb b/db/migrate/20210219021259_add_owner_to_dogs.rb new file mode 100644 index 00000000..9727c3c2 --- /dev/null +++ b/db/migrate/20210219021259_add_owner_to_dogs.rb @@ -0,0 +1,5 @@ +class AddOwnerToDogs < ActiveRecord::Migration[5.2] + def change + add_reference :dogs, :user, index: true, foreign_key: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 462bd430..353f7139 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_06_07_114248) do +ActiveRecord::Schema.define(version: 2021_02_19_021259) do create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false @@ -40,6 +40,8 @@ t.text "description" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.integer "user_id" + t.index ["user_id"], name: "index_dogs_on_user_id" end create_table "users", force: :cascade do |t| From 227ff47804200686749f8eb76f4746061339f89c Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 18:41:31 -0800 Subject: [PATCH 03/27] add will_paginate gem --- Gemfile | 2 ++ Gemfile.lock | 2 ++ app/controllers/dogs_controller.rb | 2 +- app/views/dogs/index.html.erb | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 3f1e6961..e7cc7c54 100644 --- a/Gemfile +++ b/Gemfile @@ -39,6 +39,8 @@ gem 'simple_form' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.1.0', require: false +gem 'will_paginate', '~> 3.1.0' + group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index 97a2dd53..d4677d17 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -220,6 +220,7 @@ GEM websocket-driver (0.7.0) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.3) + will_paginate (3.1.8) xpath (3.0.0) nokogiri (~> 1.8) @@ -249,6 +250,7 @@ DEPENDENCIES tzinfo-data uglifier (>= 1.3.0) web-console (>= 3.3.0) + will_paginate (~> 3.1.0) RUBY VERSION ruby 2.4.4p296 diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index cb9eebc5..ab2dbbda 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -4,7 +4,7 @@ class DogsController < ApplicationController # GET /dogs # GET /dogs.json def index - @dogs = Dog.all + @dogs = Dog.paginate(page: params[:page], per_page: 5) end # GET /dogs/1 diff --git a/app/views/dogs/index.html.erb b/app/views/dogs/index.html.erb index 91ea5603..7a01a48c 100644 --- a/app/views/dogs/index.html.erb +++ b/app/views/dogs/index.html.erb @@ -1 +1,3 @@ +<%= will_paginate @dogs %> <%= render partial: 'thumbnail', collection: @dogs, as: :dog %> +<%= will_paginate @dogs %> From 7504277c6963363738a48a917ca5a814dabd7152 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 19:12:16 -0800 Subject: [PATCH 04/27] allow multiple images --- app/controllers/dogs_controller.rb | 3 ++- app/views/dogs/_form.html.erb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index ab2dbbda..b692c20f 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -25,6 +25,7 @@ def edit # POST /dogs.json def create @dog = Dog.new(dog_params) + @dog.user = current_user respond_to do |format| if @dog.save @@ -73,6 +74,6 @@ def set_dog # Never trust parameters from the scary internet, only allow the white list through. def dog_params - params.require(:dog).permit(:name, :description, :images) + params.require(:dog).permit(:name, :description, images: []) end end diff --git a/app/views/dogs/_form.html.erb b/app/views/dogs/_form.html.erb index 6dfc7dc9..a015bf16 100644 --- a/app/views/dogs/_form.html.erb +++ b/app/views/dogs/_form.html.erb @@ -1,7 +1,7 @@ <%= simple_form_for @dog do |f| %> <%= f.input :name %> <%= f.input :description, as: :text %> - <%= f.input :image, as: :file %> + <%= f.input :images, as: :file, input_html: { multiple: true } %> <% if @dog.images.any? %> <%= image_tag @dog.images.first %> From a4f5be82520d06f55e63e6b780be2d921ed6aa82 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 19:16:32 -0800 Subject: [PATCH 05/27] only allow owners to edit/destroy dogs --- app/controllers/dogs_controller.rb | 2 ++ app/views/dogs/show.html.erb | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index b692c20f..ea9719b2 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -19,6 +19,7 @@ def new # GET /dogs/1/edit def edit + redirect_to(@dog, notice: 'You do not own this dog') unless @dog.owner == current_user end # POST /dogs @@ -59,6 +60,7 @@ def update # DELETE /dogs/1 # DELETE /dogs/1.json def destroy + redirect_to(@dog, notice: 'You do not own this dog.') unless @dog.owner == current_user @dog.destroy respond_to do |format| format.html { redirect_to dogs_url, notice: 'Dog was successfully destroyed.' } diff --git a/app/views/dogs/show.html.erb b/app/views/dogs/show.html.erb index 562324d2..54239fa7 100644 --- a/app/views/dogs/show.html.erb +++ b/app/views/dogs/show.html.erb @@ -7,7 +7,9 @@

<%= @dog.description %>

- <%= link_to "Edit #{@dog.name}'s Profile", edit_dog_path %> -
- <%= link_to "Delete #{@dog.name}'s Profile", dog_path, method: :delete, data: { confirm: 'Are you sure?' } %> + <% if @dog.owner == current_user %> + <%= link_to "Edit #{@dog.name}'s Profile", edit_dog_path %> +
+ <%= link_to "Delete #{@dog.name}'s Profile", dog_path, method: :delete, data: { confirm: 'Are you sure?' } %> + <% end %> From 76a03842d3ce0b97f21efd2beb1550c688cb17d9 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 19:18:01 -0800 Subject: [PATCH 06/27] display all images on edit page --- app/views/dogs/_form.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/dogs/_form.html.erb b/app/views/dogs/_form.html.erb index a015bf16..9c19d6ac 100644 --- a/app/views/dogs/_form.html.erb +++ b/app/views/dogs/_form.html.erb @@ -4,7 +4,9 @@ <%= f.input :images, as: :file, input_html: { multiple: true } %> <% if @dog.images.any? %> - <%= image_tag @dog.images.first %> + <% @dog.images.each do |image| %> + <%= image_tag image %> + <% end %> <% end %> <%= f.button :submit %> From 1a53f66d8a82b916138eed7945b7770d2d023e9c Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 19:21:16 -0800 Subject: [PATCH 07/27] add quick and dirty validation --- app/models/dog.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/dog.rb b/app/models/dog.rb index e358e317..8871ec8a 100644 --- a/app/models/dog.rb +++ b/app/models/dog.rb @@ -3,4 +3,9 @@ class Dog < ApplicationRecord belongs_to :user alias_method :owner, :user + + validates :name, presence: true + validates :owner, presence: true + validates :description, presence: true + validates :images, presence: true end From 7380bd14b3c3fae4cf5ac9666666e10232ebb5c2 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 20:05:51 -0800 Subject: [PATCH 08/27] show ad every 2 dogs --- app/views/dogs/_thumbnail.html.erb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/views/dogs/_thumbnail.html.erb b/app/views/dogs/_thumbnail.html.erb index 4d6bb441..f800fb87 100644 --- a/app/views/dogs/_thumbnail.html.erb +++ b/app/views/dogs/_thumbnail.html.erb @@ -1,3 +1,6 @@ +<% if dog_counter % 2 == 0 %> + <%= image_tag 'ad.jpg', class: "ad", alt: "A very cool ad." %> +<% end %>

<%= dog.name %>

From ac731cee538ef03913353193f51deb81cfd8954c Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 20:12:39 -0800 Subject: [PATCH 09/27] show ad _after_ every 2 dogs --- app/views/dogs/_thumbnail.html.erb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/dogs/_thumbnail.html.erb b/app/views/dogs/_thumbnail.html.erb index f800fb87..23aae5e9 100644 --- a/app/views/dogs/_thumbnail.html.erb +++ b/app/views/dogs/_thumbnail.html.erb @@ -1,9 +1,9 @@ -<% if dog_counter % 2 == 0 %> - <%= image_tag 'ad.jpg', class: "ad", alt: "A very cool ad." %> -<% end %>

<%= dog.name %>

<%= image_tag url_for(dog.images.first), class: "dog-photo", alt: "Photo of #{dog.name}" %>
+<% if dog_counter % 2 == 1 %> + <%= image_tag 'ad.jpg', class: "ad", alt: "A very cool ad." %> +<% end %> From d0c19ef2c4aa3cc54bf402fe523d5286e68263a9 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 20:51:44 -0800 Subject: [PATCH 10/27] add acts_as_votable gem --- Gemfile | 1 + Gemfile.lock | 2 ++ ...0210219042627_acts_as_votable_migration.rb | 22 +++++++++++++++++++ db/schema.rb | 16 +++++++++++++- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20210219042627_acts_as_votable_migration.rb diff --git a/Gemfile b/Gemfile index e7cc7c54..fc81ece6 100644 --- a/Gemfile +++ b/Gemfile @@ -40,6 +40,7 @@ gem 'simple_form' gem 'bootsnap', '>= 1.1.0', require: false gem 'will_paginate', '~> 3.1.0' +gem 'acts_as_votable' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console diff --git a/Gemfile.lock b/Gemfile.lock index d4677d17..29a904b1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -42,6 +42,7 @@ GEM i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) + acts_as_votable (0.13.1) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) arel (9.0.0) @@ -228,6 +229,7 @@ PLATFORMS ruby DEPENDENCIES + acts_as_votable bootsnap (>= 1.1.0) byebug capybara diff --git a/db/migrate/20210219042627_acts_as_votable_migration.rb b/db/migrate/20210219042627_acts_as_votable_migration.rb new file mode 100644 index 00000000..2516d700 --- /dev/null +++ b/db/migrate/20210219042627_acts_as_votable_migration.rb @@ -0,0 +1,22 @@ +class ActsAsVotableMigration < ActiveRecord::Migration[4.2] + def self.up + create_table :votes do |t| + + t.references :votable, :polymorphic => true + t.references :voter, :polymorphic => true + + t.boolean :vote_flag + t.string :vote_scope + t.integer :vote_weight + + t.timestamps + end + + add_index :votes, [:voter_id, :voter_type, :vote_scope] + add_index :votes, [:votable_id, :votable_type, :vote_scope] + end + + def self.down + drop_table :votes + end +end diff --git a/db/schema.rb b/db/schema.rb index 353f7139..8d384f7d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_02_19_021259) do +ActiveRecord::Schema.define(version: 2021_02_19_042627) do create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false @@ -62,4 +62,18 @@ t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end + create_table "votes", force: :cascade do |t| + t.string "votable_type" + t.integer "votable_id" + t.string "voter_type" + t.integer "voter_id" + t.boolean "vote_flag" + t.string "vote_scope" + t.integer "vote_weight" + t.datetime "created_at" + t.datetime "updated_at" + t.index ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope" + t.index ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope" + end + end From 6b54043f01201a393f35173ce60df5be5290915a Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 20:52:05 -0800 Subject: [PATCH 11/27] add like route --- app/controllers/dogs_controller.rb | 22 +++++++++++++++++++++- config/routes.rb | 6 +++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index ea9719b2..9e0e9a8a 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -1,5 +1,5 @@ class DogsController < ApplicationController - before_action :set_dog, only: [:show, :edit, :update, :destroy] + before_action :set_dog, only: [:show, :edit, :update, :destroy, :like] # GET /dogs # GET /dogs.json @@ -68,9 +68,29 @@ def destroy end end + # GET /dogs/1/like + # GET /dogs/1/like.json + def like + redirect_to(@dog, notice: 'You own this dog.') if @dog.owner == current_user + + if current_user.voted_for? @dog + status = 'unliked' + @dog.unliked_by current_user + else + status = 'liked' + @dog.liked_by current_user + end + + respond_to do |format| + format.html { redirect_to @dog, notice: "#{@dog.name} successfully #{status}." } + format.json { render :show, status: :ok, location: @dog } + end + end + private # Use callbacks to share common setup or constraints between actions. def set_dog + p params @dog = Dog.find(params[:id]) end diff --git a/config/routes.rb b/config/routes.rb index 06b01adc..5efc9991 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,10 @@ Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html devise_for :users - resources :dogs + resources :dogs do + member do + get "like" + end + end root to: "dogs#index" end From 065c1557e02ac29a3a47bc38a80ffeb7b81b7cf3 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 20:52:24 -0800 Subject: [PATCH 12/27] implement acts_as_votable gem --- app/models/dog.rb | 2 ++ app/models/user.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/models/dog.rb b/app/models/dog.rb index 8871ec8a..7f700256 100644 --- a/app/models/dog.rb +++ b/app/models/dog.rb @@ -8,4 +8,6 @@ class Dog < ApplicationRecord validates :owner, presence: true validates :description, presence: true validates :images, presence: true + + acts_as_votable end diff --git a/app/models/user.rb b/app/models/user.rb index 680f4357..8b379908 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,4 +5,6 @@ class User < ApplicationRecord :recoverable, :rememberable, :trackable, :validatable has_many :dogs + + acts_as_voter end From e880d8f7c4a7043b188f1e18ce3e790c77029905 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 20:52:41 -0800 Subject: [PATCH 13/27] add like/unlike button --- app/views/dogs/show.html.erb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/dogs/show.html.erb b/app/views/dogs/show.html.erb index 54239fa7..89bc59d3 100644 --- a/app/views/dogs/show.html.erb +++ b/app/views/dogs/show.html.erb @@ -11,5 +11,7 @@ <%= link_to "Edit #{@dog.name}'s Profile", edit_dog_path %>
<%= link_to "Delete #{@dog.name}'s Profile", dog_path, method: :delete, data: { confirm: 'Are you sure?' } %> + <% else %> + <%= link_to( (current_user.voted_for?(@dog) ? "💔" : "❤️"), like_dog_path(@dog)) %> <% end %> From 50dedd8fde756adf81bf50a791b874185eb03925 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 20:56:57 -0800 Subject: [PATCH 14/27] move like link next to dog name --- app/views/dogs/show.html.erb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/views/dogs/show.html.erb b/app/views/dogs/show.html.erb index 89bc59d3..a1a03003 100644 --- a/app/views/dogs/show.html.erb +++ b/app/views/dogs/show.html.erb @@ -1,5 +1,5 @@
-

<%= @dog.name %>

+

<%= @dog.name %><%= link_to( (current_user.voted_for?(@dog) ? "💔" : "❤️"), like_dog_path(@dog)) unless @dog.owner == current_user %>

<% @dog.images.each do |image| %> <%= image_tag url_for(image), alt: "Photo of #{@dog.name}" %> @@ -11,7 +11,5 @@ <%= link_to "Edit #{@dog.name}'s Profile", edit_dog_path %>
<%= link_to "Delete #{@dog.name}'s Profile", dog_path, method: :delete, data: { confirm: 'Are you sure?' } %> - <% else %> - <%= link_to( (current_user.voted_for?(@dog) ? "💔" : "❤️"), like_dog_path(@dog)) %> <% end %>
From 39889048e4f9e98d1b30e252ea3748e95ca0d907 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 21:02:16 -0800 Subject: [PATCH 15/27] add title and change emoji --- app/views/dogs/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/dogs/show.html.erb b/app/views/dogs/show.html.erb index a1a03003..5f94d11e 100644 --- a/app/views/dogs/show.html.erb +++ b/app/views/dogs/show.html.erb @@ -1,5 +1,5 @@
-

<%= @dog.name %><%= link_to( (current_user.voted_for?(@dog) ? "💔" : "❤️"), like_dog_path(@dog)) unless @dog.owner == current_user %>

+

<%= @dog.name %><%= link_to( (current_user.voted_for?(@dog) ? "❤️" : "🤍"), like_dog_path(@dog), title: "click to #{current_user.voted_for?(@dog) ? 'unlike' : 'like'}") unless @dog.owner == current_user %>

<% @dog.images.each do |image| %> <%= image_tag url_for(image), alt: "Photo of #{@dog.name}" %> From 6726b4a7395f78bd5b55e0da218c6621c88be0b9 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 21:06:06 -0800 Subject: [PATCH 16/27] remove superfluous if --- app/views/dogs/_form.html.erb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/dogs/_form.html.erb b/app/views/dogs/_form.html.erb index 9c19d6ac..54915388 100644 --- a/app/views/dogs/_form.html.erb +++ b/app/views/dogs/_form.html.erb @@ -3,10 +3,8 @@ <%= f.input :description, as: :text %> <%= f.input :images, as: :file, input_html: { multiple: true } %> - <% if @dog.images.any? %> - <% @dog.images.each do |image| %> - <%= image_tag image %> - <% end %> + <% @dog.images.each do |image| %> + <%= image_tag image %> <% end %> <%= f.button :submit %> From 727904d71c08ea41b1ec354167c69de71ec4e626 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 21:44:20 -0800 Subject: [PATCH 17/27] remove debug statement --- app/controllers/dogs_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index 9e0e9a8a..f471ce07 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -90,7 +90,6 @@ def like private # Use callbacks to share common setup or constraints between actions. def set_dog - p params @dog = Dog.find(params[:id]) end From b83e85747fe05ef490bdb06d9b24e197d5b26dfe Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 21:51:30 -0800 Subject: [PATCH 18/27] edit factories --- spec/factories/dogs.rb | 2 ++ spec/factories/user.rb | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 spec/factories/user.rb diff --git a/spec/factories/dogs.rb b/spec/factories/dogs.rb index 406874f5..79c86317 100644 --- a/spec/factories/dogs.rb +++ b/spec/factories/dogs.rb @@ -1,5 +1,7 @@ FactoryBot.define do factory :dog do + association :user + description { 'the goodest dog' } sequence :name do |n| "Good Pup #{n}" end diff --git a/spec/factories/user.rb b/spec/factories/user.rb new file mode 100644 index 00000000..dce0043a --- /dev/null +++ b/spec/factories/user.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :user do + sequence :email do |n| + "email#{n}@example.com" + end + password { '123456' } + end +end From 7401797e168bd967e127adc1cf84e869e36919ee Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Thu, 18 Feb 2021 22:05:53 -0800 Subject: [PATCH 19/27] redirect if user not signed in --- app/controllers/dogs_controller.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index f471ce07..5ffba47e 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -1,5 +1,6 @@ class DogsController < ApplicationController before_action :set_dog, only: [:show, :edit, :update, :destroy, :like] + before_action :set_user, only: [:show, :edit, :update, :destroy, :like] # GET /dogs # GET /dogs.json @@ -14,17 +15,20 @@ def show # GET /dogs/new def new + redirect_to dogs_url, notice: 'Dog was successfully destroyed.' if current_user.nil? @dog = Dog.new end # GET /dogs/1/edit def edit - redirect_to(@dog, notice: 'You do not own this dog') unless @dog.owner == current_user + redirect_to(@dog, notice: 'You do not own this dog') if current_user.nil? || @dog.owner != current_user end # POST /dogs # POST /dogs.json def create + redirect_to(@dog, notice: 'You are not signed in.') if current_user.nil? + @dog = Dog.new(dog_params) @dog.user = current_user @@ -44,6 +48,7 @@ def create # PATCH/PUT /dogs/1 # PATCH/PUT /dogs/1.json def update + redirect_to(@dog, notice: 'You do not own this dog.') if current_user.nil? || @dog.owner != current_user respond_to do |format| if @dog.update(dog_params) @dog.images.attach(params[:dog][:image]) if params[:dog][:image].present? @@ -60,7 +65,7 @@ def update # DELETE /dogs/1 # DELETE /dogs/1.json def destroy - redirect_to(@dog, notice: 'You do not own this dog.') unless @dog.owner == current_user + redirect_to(@dog, notice: 'You do not own this dog.') if current_user.nil? || @dog.owner != current_user @dog.destroy respond_to do |format| format.html { redirect_to dogs_url, notice: 'Dog was successfully destroyed.' } @@ -71,7 +76,7 @@ def destroy # GET /dogs/1/like # GET /dogs/1/like.json def like - redirect_to(@dog, notice: 'You own this dog.') if @dog.owner == current_user + redirect_to(@dog, notice: 'You own this dog.') if current_user.nil? || @dog.owner == current_user if current_user.voted_for? @dog status = 'unliked' From 51cf63e9c7d2308c32b80b1898e60025602c3c27 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 08:55:40 -0800 Subject: [PATCH 20/27] remove unused method --- app/controllers/dogs_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index 5ffba47e..19eeb2e6 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -1,6 +1,5 @@ class DogsController < ApplicationController before_action :set_dog, only: [:show, :edit, :update, :destroy, :like] - before_action :set_user, only: [:show, :edit, :update, :destroy, :like] # GET /dogs # GET /dogs.json From bc6421a9af79acbe0bb4da70a9ce752e88a0f144 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 09:13:11 -0800 Subject: [PATCH 21/27] add database cleaner --- Gemfile | 4 ++++ Gemfile.lock | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Gemfile b/Gemfile index fc81ece6..29aa7b86 100644 --- a/Gemfile +++ b/Gemfile @@ -61,6 +61,10 @@ group :development do gem 'spring-watcher-listen', '~> 2.0.0' end +group :test do + gem 'database_cleaner-active_record' +end + # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/Gemfile.lock b/Gemfile.lock index 29a904b1..20882829 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -69,6 +69,10 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.0.5) crass (1.0.4) + database_cleaner-active_record (2.0.0) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) devise (4.4.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) @@ -234,6 +238,7 @@ DEPENDENCIES byebug capybara coffee-rails (~> 4.2) + database_cleaner-active_record devise factory_bot_rails jbuilder (~> 2.5) From 14179063548357bd07c6641129b8848f566f3217 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 09:14:26 -0800 Subject: [PATCH 22/27] don't show edit/delete/link links if current_user is nil --- app/views/dogs/show.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/dogs/show.html.erb b/app/views/dogs/show.html.erb index 5f94d11e..a1602a30 100644 --- a/app/views/dogs/show.html.erb +++ b/app/views/dogs/show.html.erb @@ -1,5 +1,5 @@
-

<%= @dog.name %><%= link_to( (current_user.voted_for?(@dog) ? "❤️" : "🤍"), like_dog_path(@dog), title: "click to #{current_user.voted_for?(@dog) ? 'unlike' : 'like'}") unless @dog.owner == current_user %>

+

<%= @dog.name %><%= link_to( (current_user&.voted_for?(@dog) ? "❤️" : "🤍"), like_dog_path(@dog), title: "click to #{current_user&.voted_for?(@dog) ? 'unlike' : 'like'}") unless current_user.nil? || @dog.owner == current_user %>

<% @dog.images.each do |image| %> <%= image_tag url_for(image), alt: "Photo of #{@dog.name}" %> @@ -7,7 +7,7 @@

<%= @dog.description %>

- <% if @dog.owner == current_user %> + <% if current_user && @dog.owner == current_user %> <%= link_to "Edit #{@dog.name}'s Profile", edit_dog_path %>
<%= link_to "Delete #{@dog.name}'s Profile", dog_path, method: :delete, data: { confirm: 'Are you sure?' } %> From 8aca9a61ea64efce5a051b7eb6c2c254c4e61781 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 09:14:45 -0800 Subject: [PATCH 23/27] configure database cleaner --- spec/rails_helper.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 4e322aeb..535e3e37 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -56,4 +56,16 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") + + config.before(:suite) do + DatabaseCleaner.strategy = :transaction + DatabaseCleaner.clean_with(:truncation) + end + + config.around(:each) do |example| + DatabaseCleaner.cleaning do + example.run + end + end + end From 97f8d34b42b00dcc84ca165af644e258e341bfd9 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 09:15:06 -0800 Subject: [PATCH 24/27] login with devise for spec --- spec/features/dog_resource_spec.rb | 8 ++++++-- spec/rails_helper.rb | 7 +++++++ spec/support/controller_macros.rb | 9 +++++++++ spec/support/devise.rb | 9 +++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 spec/support/controller_macros.rb create mode 100644 spec/support/devise.rb diff --git a/spec/features/dog_resource_spec.rb b/spec/features/dog_resource_spec.rb index d9337477..8f428779 100644 --- a/spec/features/dog_resource_spec.rb +++ b/spec/features/dog_resource_spec.rb @@ -1,6 +1,10 @@ require 'rails_helper' +require_relative '../support/devise' describe 'Dog resource', type: :feature do + let!(:spec_user) { User.first || FactoryBot.create(:user) } + before { login_as spec_user } + it 'can create a profile' do visit new_dog_path fill_in 'Name', with: 'Speck' @@ -11,7 +15,7 @@ end it 'can edit a dog profile' do - dog = create(:dog) + dog = create(:dog, user: spec_user) visit edit_dog_path(dog) fill_in 'Name', with: 'Speck' click_button 'Update Dog' @@ -19,7 +23,7 @@ end it 'can delete a dog profile' do - dog = create(:dog) + dog = create(:dog, user: spec_user) visit dog_path(dog) click_link "Delete #{dog.name}'s Profile" expect(Dog.count).to eq(0) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 535e3e37..3642aba5 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -56,6 +56,13 @@ config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") + config.expect_with :rspec do |c| + c.syntax = :expect + end + + config.include Devise::Test::ControllerHelpers, :type => :controller + + config.include Warden::Test::Helpers config.before(:suite) do DatabaseCleaner.strategy = :transaction diff --git a/spec/support/controller_macros.rb b/spec/support/controller_macros.rb new file mode 100644 index 00000000..e0da1ab8 --- /dev/null +++ b/spec/support/controller_macros.rb @@ -0,0 +1,9 @@ +module ControllerMacros + def login_user + before(:each) do + @request.env["devise.mapping"] = Devise.mappings[:user] + user = FactoryBot.create(:user) + sign_in user + end + end +end diff --git a/spec/support/devise.rb b/spec/support/devise.rb new file mode 100644 index 00000000..888c28b3 --- /dev/null +++ b/spec/support/devise.rb @@ -0,0 +1,9 @@ +require_relative './controller_macros' # or require_relative './controller_macros' if write in `spec/support/devise.rb` + +RSpec.configure do |config| + # For Devise > 4.1.1 + config.include Devise::Test::ControllerHelpers, :type => :controller + # Use the following instead if you are on Devise <= 4.1.1 + # config.include Devise::TestHelpers, :type => :controller + config.extend ControllerMacros, :type => :controller +end From ab6ba7fb22f7accd684dcc83e95ec650c3558912 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 09:35:23 -0800 Subject: [PATCH 25/27] add sort by likes --- app/controllers/dogs_controller.rb | 8 +++++++- app/views/dogs/index.html.erb | 5 +++++ .../20210220172412_add_cached_votes_to_dogs.rb | 16 ++++++++++++++++ db/schema.rb | 9 ++++++++- 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20210220172412_add_cached_votes_to_dogs.rb diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index 19eeb2e6..6f19f840 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -4,7 +4,13 @@ class DogsController < ApplicationController # GET /dogs # GET /dogs.json def index - @dogs = Dog.paginate(page: params[:page], per_page: 5) + if params[:sort] == 'likes' + dogs = Dog.order(:cached_weighted_average => :desc) + else + dogs = Dog + end + @sorted = params[:sort] == 'likes' + @dogs = dogs.paginate(page: params[:page], per_page: 5) end # GET /dogs/1 diff --git a/app/views/dogs/index.html.erb b/app/views/dogs/index.html.erb index 7a01a48c..aa08f33d 100644 --- a/app/views/dogs/index.html.erb +++ b/app/views/dogs/index.html.erb @@ -1,3 +1,8 @@ +<% if @sorted %> + <%= link_to "Unsort", root_path, title: "sort by likes", id: 'sort' %> +<% else %> + <%= link_to "Sort by Likes", root_path + '?sort=likes', title: "unsort by likes", id: 'sort' %> +<% end %> <%= will_paginate @dogs %> <%= render partial: 'thumbnail', collection: @dogs, as: :dog %> <%= will_paginate @dogs %> diff --git a/db/migrate/20210220172412_add_cached_votes_to_dogs.rb b/db/migrate/20210220172412_add_cached_votes_to_dogs.rb new file mode 100644 index 00000000..d6cae834 --- /dev/null +++ b/db/migrate/20210220172412_add_cached_votes_to_dogs.rb @@ -0,0 +1,16 @@ +class AddCachedVotesToDogs < ActiveRecord::Migration[5.2] + def change + change_table :dogs do |t| + t.integer :cached_votes_total, default: 0 + t.integer :cached_votes_score, default: 0 + t.integer :cached_votes_up, default: 0 + t.integer :cached_votes_down, default: 0 + t.integer :cached_weighted_score, default: 0 + t.integer :cached_weighted_total, default: 0 + t.float :cached_weighted_average, default: 0.0 + end + + # Uncomment this line to force caching of existing votes + Dog.find_each(&:update_cached_votes) + end +end diff --git a/db/schema.rb b/db/schema.rb index 8d384f7d..542af6a9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_02_19_042627) do +ActiveRecord::Schema.define(version: 2021_02_20_172412) do create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false @@ -41,6 +41,13 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "user_id" + t.integer "cached_votes_total", default: 0 + t.integer "cached_votes_score", default: 0 + t.integer "cached_votes_up", default: 0 + t.integer "cached_votes_down", default: 0 + t.integer "cached_weighted_score", default: 0 + t.integer "cached_weighted_total", default: 0 + t.float "cached_weighted_average", default: 0.0 t.index ["user_id"], name: "index_dogs_on_user_id" end From 0bc67d7915a0fdb3ce4b2b87af67470a3e5c88bf Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 09:35:42 -0800 Subject: [PATCH 26/27] make like/unlike links cleaner --- app/views/dogs/show.html.erb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/views/dogs/show.html.erb b/app/views/dogs/show.html.erb index a1602a30..2dea1231 100644 --- a/app/views/dogs/show.html.erb +++ b/app/views/dogs/show.html.erb @@ -1,5 +1,14 @@
-

<%= @dog.name %><%= link_to( (current_user&.voted_for?(@dog) ? "❤️" : "🤍"), like_dog_path(@dog), title: "click to #{current_user&.voted_for?(@dog) ? 'unlike' : 'like'}") unless current_user.nil? || @dog.owner == current_user %>

+

+ <%= @dog.name %> + <% unless current_user.nil? || @dog.owner == current_user %> + <% if current_user&.voted_for?(@dog) %> + <%= link_to "❤️", like_dog_path(@dog), title: "click to unlike", id: 'like_dog_link' %> + <% else %> + <%= link_to "🤍", like_dog_path(@dog), title: "click to like", id: 'unlike_dog_link' %> + <% end %> + <% end %> +

<% @dog.images.each do |image| %> <%= image_tag url_for(image), alt: "Photo of #{@dog.name}" %> From 767b0a505b721b9b092e32e02d019d45114322d6 Mon Sep 17 00:00:00 2001 From: Pat Holland Date: Sat, 20 Feb 2021 09:36:53 -0800 Subject: [PATCH 27/27] remove repetitive message from like/unlike dogs --- app/controllers/dogs_controller.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/dogs_controller.rb b/app/controllers/dogs_controller.rb index 6f19f840..fb2c50b7 100644 --- a/app/controllers/dogs_controller.rb +++ b/app/controllers/dogs_controller.rb @@ -84,15 +84,13 @@ def like redirect_to(@dog, notice: 'You own this dog.') if current_user.nil? || @dog.owner == current_user if current_user.voted_for? @dog - status = 'unliked' @dog.unliked_by current_user else - status = 'liked' @dog.liked_by current_user end respond_to do |format| - format.html { redirect_to @dog, notice: "#{@dog.name} successfully #{status}." } + format.html { redirect_to @dog } format.json { render :show, status: :ok, location: @dog } end end