From 57c457853374b665c1730867aef18199ca8bd9fc Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 14:06:05 +0100 Subject: [PATCH 01/10] added relationship model --- app/models/relationship.rb | 2 ++ db/migrate/20141130130221_create_relationships.rb | 14 ++++++++++++++ db/schema.rb | 13 ++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 app/models/relationship.rb create mode 100644 db/migrate/20141130130221_create_relationships.rb diff --git a/app/models/relationship.rb b/app/models/relationship.rb new file mode 100644 index 00000000..210bc921 --- /dev/null +++ b/app/models/relationship.rb @@ -0,0 +1,2 @@ +class Relationship < ActiveRecord::Base +end diff --git a/db/migrate/20141130130221_create_relationships.rb b/db/migrate/20141130130221_create_relationships.rb new file mode 100644 index 00000000..838d0fea --- /dev/null +++ b/db/migrate/20141130130221_create_relationships.rb @@ -0,0 +1,14 @@ +class CreateRelationships < ActiveRecord::Migration + def change + create_table :relationships do |t| + t.integer :source_id + t.integer :target_id + + t.timestamps + end + + add_index :relationships, :source_id + add_index :relationships, :target_id + add_index :relationships, [:source_id, :target_id], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 3b8da33b..83c90912 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20141129211448) do +ActiveRecord::Schema.define(version: 20141130130221) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -59,6 +59,17 @@ ActiveRecord::Schema.define(version: 20141129211448) do add_index "questions", ["user_id", "created_at"], name: "index_questions_on_user_id_and_created_at", using: :btree + create_table "relationships", force: true do |t| + t.integer "source_id" + t.integer "target_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "relationships", ["source_id", "target_id"], name: "index_relationships_on_source_id_and_target_id", unique: true, using: :btree + add_index "relationships", ["source_id"], name: "index_relationships_on_source_id", using: :btree + add_index "relationships", ["target_id"], name: "index_relationships_on_target_id", using: :btree + create_table "users", force: true do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false From eecdecfda966c6e923db4dc1f63a127e613da976 Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 14:43:35 +0100 Subject: [PATCH 02/10] added validations and everything --- app/models/relationship.rb | 4 ++++ app/models/user.rb | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/relationship.rb b/app/models/relationship.rb index 210bc921..20dec636 100644 --- a/app/models/relationship.rb +++ b/app/models/relationship.rb @@ -1,2 +1,6 @@ class Relationship < ActiveRecord::Base + belongs_to :source, class_name: 'User' + belongs_to :target, class_name: 'User' + validates :source_id, presence: true + validates :target_id, presence: true end diff --git a/app/models/user.rb b/app/models/user.rb index 9cd79bec..3858c8a2 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -11,7 +11,15 @@ class User < ActiveRecord::Base has_many :answers, dependent: :destroy has_many :comments, dependent: :destroy has_many :inboxes, dependent: :destroy - + has_many :active_relationships, class_name: 'Relationship', + foreign_key: 'source_id', + dependent: :destroy + has_many :passive_relationships, class_name: 'Relationship', + foreign_key: 'target_id', + dependent: :destroy + has_many :friends, through: :active_relationships, source: :target + has_many :followers, through: :passive_relationships, source: :source + SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]{1,16}\z/ validates :screen_name, presence: true, format: { with: SCREEN_NAME_REGEX }, uniqueness: { case_sensitive: false } From 4db8f8f33f8bf8b14d0a2202764bd6adb5b00284 Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 14:45:32 +0100 Subject: [PATCH 03/10] added some Ajax routes --- app/controllers/ajax/friend_controller.rb | 13 +++++++++++++ config/routes.rb | 2 ++ 2 files changed, 15 insertions(+) create mode 100644 app/controllers/ajax/friend_controller.rb diff --git a/app/controllers/ajax/friend_controller.rb b/app/controllers/ajax/friend_controller.rb new file mode 100644 index 00000000..a632a9d4 --- /dev/null +++ b/app/controllers/ajax/friend_controller.rb @@ -0,0 +1,13 @@ +class Ajax::FriendController < ApplicationController + def create + @status = :okay + @message = "Successfully followed user." + @success = true + end + + def destroy + @status = :okay + @message = "Successfully unfollowed user." + @success = true + end +end diff --git a/config/routes.rb b/config/routes.rb index 65a6b651..d316dadc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -27,6 +27,8 @@ Rails.application.routes.draw do match '/ask', to: 'question#create', via: :post, as: :ask match '/answer', to: 'inbox#destroy', via: :post, as: :answer match '/destroy_answer', to: 'answer#destroy', via: :post, as: :destroy_answer + match '/create_friend', to: 'friend#create', via: :post, as: :create_friend + match '/destroy_friend', to: 'friend#destroy', via: :post, as: :destroy_friend end match '/inbox', to: 'inbox#show', via: 'get' From 63be00f70fa9d2926a28de4ec6123219c6bbde2b Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 14:56:06 +0100 Subject: [PATCH 04/10] justask:recount now recounts the friend/follower_count --- Rakefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rakefile b/Rakefile index 7e6c3f34..1afced0b 100644 --- a/Rakefile +++ b/Rakefile @@ -15,6 +15,8 @@ namespace :justask do answered = Answer.where(user: user).count asked = Question.where(user: user).where(author_is_anonymous: false).count commented = Comment.where(user: user).count + user.friend_count = user.friends.count + user.follower_count = user.followers.count user.answered_count = answered user.asked_count = asked user.commented_count = commented From 928addf5db9f1ed0d9e796750158797c15293bd8 Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 15:13:17 +0100 Subject: [PATCH 05/10] added methods for following/unfollowing users --- app/models/user.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 3858c8a2..69305a6e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -42,4 +42,26 @@ class User < ActiveRecord::Base where(conditions).first end end + + # follows an user. + def follow(target_user) + active_relationships.create(target: target_user) + + # increment counts + increment! :friend_count + target_user.increment! :follower_count + end + + def unfollow(target_user) + active_relationships.find_by(target: target_user).destroy + + # decrement counts + decrement! :friend_count + target_user.decrement! :follower_count + end + + # @return [Boolean] true if +current_user+ is following +target_user+ + def following?(target_user) + friends.include? target_user + end end From 1b15add6b1a44ae0afb0b6205e830fc604501f68 Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 15:13:37 +0100 Subject: [PATCH 06/10] added ajax controller thing --- app/controllers/ajax/friend_controller.rb | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app/controllers/ajax/friend_controller.rb b/app/controllers/ajax/friend_controller.rb index a632a9d4..c6e50fef 100644 --- a/app/controllers/ajax/friend_controller.rb +++ b/app/controllers/ajax/friend_controller.rb @@ -1,11 +1,37 @@ class Ajax::FriendController < ApplicationController def create + params.require :screen_name + + target_user = User.find_by_screen_name(params[:screen_name]) + + begin + current_user.follow target_user + rescue + @status = :fail + @message = "You are already following that user." + @success = false + return + end + @status = :okay @message = "Successfully followed user." @success = true end def destroy + params.require :screen_name + + target_user = User.find_by_screen_name(params[:screen_name]) + + begin + current_user.unfollow target_user + rescue + @status = :fail + @message = "You are not following that user." + @success = false + return + end + @status = :okay @message = "Successfully unfollowed user." @success = true From d4c1ce83de27c7a1b5c14ee05f32c781b8ae939e Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 15:28:38 +0100 Subject: [PATCH 07/10] added ids to counts --- app/views/user/show.html.haml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/views/user/show.html.haml b/app/views/user/show.html.haml index aaf9223f..69fa9d70 100644 --- a/app/views/user/show.html.haml +++ b/app/views/user/show.html.haml @@ -14,14 +14,15 @@ %p.user-admin %i.fa.fa-flask Admin - %h4.entry-text= @user.follower_count - %h6.entry-subtext Followers - %h4.entry-text= @user.friend_count - %h6.entry-subtext Followings - %h4.entry-text= @user.asked_count + %h4.entry-text#follower-count= @user.follower_count + %h6.entry-subtext Follower + %h4.entry-text#friend-count= @user.friend_count + %h6.entry-subtext Following + %h4.entry-text#asked-count= @user.asked_count %h6.entry-subtext Questions - %h4.entry-text= @user.answered_count + %h4.entry-text#answered-count= @user.answered_count %h6.entry-subtext Answers + = render 'user/actions' .hidden-xs= render 'shared/links' .col-md-9.col-xs-12.col-sm-9 = render 'shared/questionbox' From 81c4f14a62fa9709aa83edb9774546a58465d861 Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 15:28:58 +0100 Subject: [PATCH 08/10] added user/actions partial --- app/views/user/_actions.html.haml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 app/views/user/_actions.html.haml diff --git a/app/views/user/_actions.html.haml b/app/views/user/_actions.html.haml new file mode 100644 index 00000000..584a1de1 --- /dev/null +++ b/app/views/user/_actions.html.haml @@ -0,0 +1,10 @@ +- if user_signed_in? + - if @user == current_user + %a.btn.btn-default.btn-block{href: edit_user_profile_path} Edit profile + - else + - if current_user.following? @user + %button#editprofile.btn.btn-default.btn-block{type: :button, name: 'user-action', 'data-action' => :unfollow, 'data-target' => @user.screen_name} + Unfollow + - else + %button#editprofile.btn.btn-primary.btn-block{type: :button, name: 'user-action', 'data-action' => :follow, 'data-target' => @user.screen_name} + Follow \ No newline at end of file From 814a509f60128a942ccdb8e441a242a28c502a56 Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 15:34:23 +0100 Subject: [PATCH 09/10] added JS for following/unfollowing --- .../javascripts/application.js.erb.coffee | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/application.js.erb.coffee b/app/assets/javascripts/application.js.erb.coffee index 84a3a63a..f2e4e380 100644 --- a/app/assets/javascripts/application.js.erb.coffee +++ b/app/assets/javascripts/application.js.erb.coffee @@ -72,7 +72,6 @@ $(document).on "click", "button[name=ib-answer]", -> btn.button "reset" $("textarea[name=ib-answer][data-id=#{iid}]").removeAttr "readonly" -# TODO $(document).on "click", "button[name=ab-destroy]", -> btn = $(this) btn.button "loading" @@ -92,6 +91,49 @@ $(document).on "click", "button[name=ab-destroy]", -> complete: (jqxhr, status) -> btn.button "reset" +$(document).on "click", "button[name=user-action]", -> + btn = $(this) + btn.button "loading" + target = btn[0].dataset.target + action = btn[0].dataset.action + count = Number($("h4.entry-text#follower-count").html()) + + target_url = switch action + when 'follow' + count++ + '/ajax/create_friend' + when 'unfollow' + count-- + '/ajax/destroy_friend' + + success = false + + $.ajax + url: target_url + type: 'POST' + data: + screen_name: target + success: (data, status, jqxhr) -> + success = data.success + if data.success + $("h4.entry-text#follower-count").html(count) + showNotification data.message, data.success + error: (jqxhr, status, error) -> + console.log jqxhr, status, error + showNotification "An error occurred, a developer should check the console for details", false + complete: (jqxhr, status) -> + btn.button "reset" + if success + switch action + when 'follow' + btn[0].dataset.action = 'unfollow' + btn.attr 'class', 'btn btn-default btn-block' + btn.html 'Unfollow' + when 'unfollow' + btn[0].dataset.action = 'follow' + btn.attr 'class', 'btn btn-primary btn-block' + btn.html 'Follow' + $(document).on "click", "button#create-account", -> Turbolinks.visit "/sign_up" From e8974415c9641daa57c3bc56158781ba166f33b6 Mon Sep 17 00:00:00 2001 From: nilsding Date: Sun, 30 Nov 2014 15:39:13 +0100 Subject: [PATCH 10/10] timeline now actually shows entries --- app/models/user.rb | 6 ++++++ app/views/static/index.html.haml | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 69305a6e..4795c9ba 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -43,6 +43,11 @@ class User < ActiveRecord::Base end end + # @return [Array] the users' timeline + def timeline + Answer.where("user_id in (?) OR user_id = ?", friend_ids, id).order(:created_at).reverse_order + end + # follows an user. def follow(target_user) active_relationships.create(target: target_user) @@ -52,6 +57,7 @@ class User < ActiveRecord::Base target_user.increment! :follower_count end + # unfollows an user def unfollow(target_user) active_relationships.find_by(target: target_user).destroy diff --git a/app/views/static/index.html.haml b/app/views/static/index.html.haml index 11a442ad..64516ae7 100644 --- a/app/views/static/index.html.haml +++ b/app/views/static/index.html.haml @@ -1,9 +1,10 @@ - if user_signed_in? .container - %h1 Static#index + %h1 Timeline = render 'layouts/messages' - %p Find me in app/views/static/index.html.haml + - current_user.timeline.each do |answer| + = render 'shared/answerbox', a: answer = render "shared/links" - else .jumbotron