Skip to content

Commit

Permalink
Implement like feature for Replies. #34
Browse files Browse the repository at this point in the history
Remove Like collection, embeded likes info in liketable as an Array field.
Remove likes_count from User.
  • Loading branch information
huacnlee committed Jun 6, 2012
1 parent dc2083d commit 150f1e8
Show file tree
Hide file tree
Showing 14 changed files with 104 additions and 93 deletions.
18 changes: 13 additions & 5 deletions app/assets/javascripts/app.coffee
Expand Up @@ -37,9 +37,13 @@ window.App =
type : likeable_type
id : likeable_id
success : (re) ->
if parseInt(re) >= 0
likes_count = parseInt(re)
if likes_count >= 0
$(el).data("state","liked").attr("title", "取消喜欢")
$('span',el).text("#{re}人喜欢")
if likes_count == 0
$('span',el).text("喜欢")
else
$('span',el).text("#{re}人喜欢")
$("i.icon",el).attr("class","icon small_liked")
else
App.alert("抱歉,系统异常,提交失败。")
Expand All @@ -50,9 +54,13 @@ window.App =
data :
type : likeable_type
success : (re) ->
if parseInt(re) >= 0
likes_count = parseInt(re)
if likes_count >= 0
$(el).data("state","").attr("title", "喜欢")
$('span',el).text("#{re}人喜欢")
if likes_count == 0
$('span',el).text("喜欢")
else
$('span',el).text("#{re}人喜欢")
$("i.icon",el).attr("class","icon small_like")
else
App.alert("抱歉,系统异常,提交失败。")
Expand Down Expand Up @@ -90,7 +98,7 @@ $(document).ready ->
App.initForDesktopView()

$("abbr.timeago").timeago()
$(".alert").alert()
$(".alert").alert()
$('.dropdown-toggle').dropdown()


Expand Down
18 changes: 14 additions & 4 deletions app/assets/stylesheets/topics.scss
Expand Up @@ -39,6 +39,7 @@
text-align:right; height:16px; overflow:hidden;
a:link,
a:visited {
margin-left:5px;
i { position:relative; margin-bottom:-1px; }
text-decoration: none;
}
Expand Down Expand Up @@ -130,22 +131,31 @@ form .node_select {
#replies {
.total { padding-bottom:6px; color:#999; }
.reply {
&.light { background:#F7F2FC; }
&.popular { background:#fffce9; }
border-top:1px solid #DDD; padding:8px 10px; margin:0 -10px;
.face { padding-right:8px; width:48px; margin-left:0; }
.infos { padding-left:58px; }
.info {
margin-top:4px; color:#999;height:20px;
a:link,
a:visited { color:#999; text-decoration: underline;}
.name { float:left; }
.time { float:right; text-align:right; }
a:visited { color:#999; }
.name {
float:left;
a { text-decoration:underline; margin-right:8px; }
}
.opts {
float:right; text-align:right;
a { margin-left:5px; }
a:hover { text-decoration:none; }
i.icon { margin-bottom:-1px; }
}
a.reply_link img { vertical-align:middle;}
}
.body {
img { max-width:622px;}
}
}
.reply.light { background:#F7F2FC;}
}

#reply.form {
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/likes_controller.rb
Expand Up @@ -17,7 +17,7 @@ def destroy
def find_likeable
@success = false
@element_id = "likeable_#{params[:type]}_#{params[:id]}"
if not params[:type].in?(['Topic'])
if not params[:type].in?(['Topic','Reply'])
render :text => "-1"
return false
end
Expand Down
6 changes: 5 additions & 1 deletion app/helpers/likes_helper.rb
Expand Up @@ -4,6 +4,10 @@ module LikesHelper
def likeable_tag(likeable)
return "" if likeable.blank?

label = "#{likeable.likes_count}人喜欢"
if likeable.likes_count == 0
label = "喜欢"
end
if current_user && likeable.liked_by_user?(current_user)
title = "取消喜欢"
state = "liked"
Expand All @@ -13,7 +17,7 @@ def likeable_tag(likeable)
state = ""
icon = content_tag("i", "", :class => "icon small_like")
end
like_label = raw "#{icon} <span>#{likeable.likes_count}人喜欢</span>"
like_label = raw "#{icon} <span>#{label}</span>"
link_to(like_label,"#",:title => title, :rel => "twipsy",
'data-state' => state,'data-type' => likeable.class,'data-id' => likeable.id,
:class => 'likeable', :onclick => "return App.likeable(this);")
Expand Down
10 changes: 9 additions & 1 deletion app/models/mongoid/likeable.rb
@@ -1,8 +1,16 @@
# coding: utf-8
module Mongoid
module Likeable
extend ActiveSupport::Concern

included do
field :liked_user_ids, :type => Array, :default => []
field :likes_count, :type => Integer, :default => 0
end

def liked_by_user?(user)
Like.where(:likeable_type => self.class, :likeable_id => self.id, :user_id => user.id).count > 0
return false if user.blank?
self.liked_user_ids.include?(user.id)
end
end
end
7 changes: 7 additions & 0 deletions app/models/reply.rb
Expand Up @@ -8,11 +8,13 @@ class Reply
include Mongoid::SoftDelete
include Mongoid::MarkdownBody
include Mongoid::Mentionable
include Mongoid::Likeable

field :body
field :body_html
field :source
field :message_id
field :likes_count, :type => Integer, :default => 0

This comment has been minimized.

Copy link
@huobazi

huobazi Jun 7, 2012

Contributor

@huacnlee 为什么这里加上了 likes_count, 但 topic.rb 内却去掉了 likes_count, 这个likes_count 不是都在 Likeable 内定义 include 了吗?

This comment has been minimized.

Copy link
@huacnlee

huacnlee Jun 7, 2012

Author Member

笔误,可以不要的


belongs_to :user, :inverse_of => :replies
belongs_to :topic, :inverse_of => :replies
Expand Down Expand Up @@ -59,6 +61,11 @@ def send_topic_reply_notification
end
end

# 是否热门
def popular?
self.likes_count >= 5
end

def destroy
super
notifications.delete_all
Expand Down
1 change: 0 additions & 1 deletion app/models/topic.rb
Expand Up @@ -22,7 +22,6 @@ class Topic
# 回复过的人的 ids 列表
field :follower_ids, :type => Array, :default => []
field :suggested_at, :type => DateTime
field :likes_count, :type => Integer, :default => 0
# 最后回复人的用户名 - cache 字段用于减少列表也的查询
field :last_reply_user_login
# 节点名称 - cache 字段用于减少列表也的查询
Expand Down
16 changes: 8 additions & 8 deletions app/models/user.rb
Expand Up @@ -29,7 +29,6 @@ class User
field :tagline
field :topics_count, :type => Integer, :default => 0
field :replies_count, :type => Integer, :default => 0
field :likes_count, :type => Integer, :default => 0
# 用户密钥,用于客户端验证
field :private_token
field :favorite_topic_ids, :type => Array, :default => []
Expand All @@ -48,7 +47,6 @@ class User
has_many :posts
has_many :notifications, :class_name => 'Notification::Base', :dependent => :delete
has_many :photos
has_many :likes

def read_notifications(notifications)
unread_ids = notifications.find_all{|notification| !notification.read?}.map(&:_id)
Expand Down Expand Up @@ -191,16 +189,18 @@ def read_topic(topic)

# 收藏东西
def like(likeable)
Like.find_or_create_by(:likeable_id => likeable.id,
:likeable_type => likeable.class,
:user_id => self.id)
return false if likeable.blank?
return false if likeable.liked_by_user?(self)
likeable.push(:liked_user_ids, self.id)
likeable.inc(:likes_count, 1)
end

# 取消收藏
def unlike(likeable)
Like.where(:likeable_id => likeable.id,
:likeable_type => likeable.class,
:user_id => self.id).destroy
return false if likeable.blank?
return false if not likeable.liked_by_user?(self)
likeable.pull(:liked_user_ids, self.id)
likeable.inc(:likes_count, -1)
end

# 收藏话题
Expand Down
11 changes: 8 additions & 3 deletions app/views/replies/_reply.html.erb
@@ -1,10 +1,13 @@
<div class="reply" id="reply<%= reply_counter + 1 %>">
<div class="reply<%= ' popular' if reply.popular? %>" id="reply<%= reply_counter + 1 %>">
<div class="pull-left face"><%= user_avatar_tag(reply.user, :normal) %></div>
<div class="infos">
<div class="info">
<span class="name"><%= user_name_tag(reply.user) %></span>
<span class="time">
<span class="name">
<%= user_name_tag(reply.user) %>
<%= reply_counter + 1 %><%= t("common.floor")%>, <%= raw t("common.reply_at", :time => timeago(reply.created_at)) %>
</span>
<span class="opts">
<%= likeable_tag(reply) %>
<% if can?(:update,reply) %>
<%= link_to("", edit_topic_reply_path(@topic,reply), :class => "edit icon small_edit", 'data-uid' => reply.user_id, :title => "修改回帖")%>
<% end %>
Expand All @@ -17,5 +20,7 @@
<div class="body">
<%= raw reply.body_html %>
</div>
<span class="opts">
</span>
</div>
</div>
19 changes: 0 additions & 19 deletions db/migrate/20120422061501_reply_mention_to_mentionable.rb

This file was deleted.

7 changes: 0 additions & 7 deletions db/migrate/20120513024148_remove_old_topic_followers.rb

This file was deleted.

4 changes: 3 additions & 1 deletion spec/helpers/likes_helper_spec.rb
Expand Up @@ -14,12 +14,14 @@
it "should result when logined user liked" do
helper.stub(:current_user).and_return(user)
topic.stub(:liked_by_user?).and_return(true)
helper.likeable_tag(topic).should == %(<a href="#" class="likeable" data-id="#{topic.id}" data-state="liked" data-type="#{topic.class}" onclick="return App.likeable(this);" rel="twipsy" title="取消喜欢"><i class="icon small_liked"></i> <span>喜欢</span></a>)
topic.stub!(:likes_count).and_return(3)
helper.likeable_tag(topic).should == %(<a href="#" class="likeable" data-id="#{topic.id}" data-state="liked" data-type="#{topic.class}" onclick="return App.likeable(this);" rel="twipsy" title="取消喜欢"><i class="icon small_liked"></i> <span>#{topic.likes_count}人喜欢</span></a>)
end

it "should result when unlogin user" do
helper.stub(:current_user).and_return(nil)
helper.likeable_tag(topic).should == %(<a href="#" class="likeable" data-id="#{topic.id}" data-state="" data-type="#{topic.class}" onclick="return App.likeable(this);" rel="twipsy" title="喜欢"><i class="icon small_like"></i> <span>#{topic.likes_count}人喜欢</span></a>)
helper.likeable_tag(topic).should == %(<a href="#" class="likeable" data-id="#{topic.id}" data-state="" data-type="#{topic.class}" onclick="return App.likeable(this);" rel="twipsy" title="喜欢"><i class="icon small_like"></i> <span>喜欢</span></a>)
end
end
end
37 changes: 0 additions & 37 deletions spec/models/like_spec.rb

This file was deleted.

41 changes: 36 additions & 5 deletions spec/models/user_spec.rb
Expand Up @@ -39,7 +39,7 @@
user_for_delete1.authorizations.should == []
end
end

describe "location" do
it "should not get results when user location not set" do
Location.count == 0
Expand All @@ -50,7 +50,7 @@
user2.location = "Hongkong"
Location.count == 2
end

it "should update users_count when user location changed" do
old_name = user.location
new_name = "HongKong"
Expand Down Expand Up @@ -141,22 +141,53 @@
user.private_token.should_not == old_token
end
end

describe "favorite topic" do
it "should favorite a topic" do
user.favorite_topic(topic.id)
user.favorite_topic_ids.include?(topic.id).should == true

user.favorite_topic(nil).should == false
user.favorite_topic(topic.id.to_s).should == false
user.favorite_topic_ids.include?(topic.id).should == true
end

it "should unfavorite a topic" do
user.unfavorite_topic(topic.id)
user.favorite_topic_ids.include?(topic.id).should == false
user.unfavorite_topic(nil).should == false
user.unfavorite_topic(topic.id.to_s).should == true
end
end

describe "Like" do
let(:topic) { Factory :topic }
let(:user) { Factory :user }
let(:user2) { Factory :user }

describe "like topic" do
it "can like/unlike topic" do
user.like(topic)
topic.reload
topic.likes_count.should == 1
topic.liked_user_ids.should include(user.id)

user2.like(topic)
topic.reload
topic.likes_count.should == 2
topic.liked_user_ids.should include(user2.id)

user2.unlike(topic)
topic.reload
topic.likes_count.should == 1
topic.liked_user_ids.should_not include(user2.id)
end

it "can tell whether or not liked by a user" do
topic.liked_by_user?(user).should be_false
user.like(topic)
topic.liked_by_user?(user).should be_true
end
end
end
end

0 comments on commit 150f1e8

Please sign in to comment.