Merge branch 'follow-users' into 'master'

Follow users

See merge request !1
This commit is contained in:
Georg G 2014-11-30 15:40:18 +01:00
commit be8a9fdc10
11 changed files with 175 additions and 11 deletions

View File

@ -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

View File

@ -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"

View File

@ -0,0 +1,39 @@
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
end
end

View File

@ -0,0 +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

View File

@ -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 }
@ -34,4 +42,32 @@ class User < ActiveRecord::Base
where(conditions).first
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)
# increment counts
increment! :friend_count
target_user.increment! :follower_count
end
# unfollows an user
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

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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'

View File

@ -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

View File

@ -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