Commit 94018746 by Rocky Duan

use thumbs_up

parent 3d8d780d
......@@ -12,6 +12,8 @@ gem 'sqlite3'
gem 'ampex'
gem 'thumbs_up', :git => "git@github.com:dementrock/thumbs_up.git"
group :test do
gem 'rspec'
gem 'rack-test', :require => "rack/test"
......
......@@ -2,10 +2,12 @@ require 'rubygems'
require 'yajl'
require 'active_record'
require 'sinatra'
require 'thumbs_up'
require_relative 'models/comment'
require_relative 'models/comment_thread'
require_relative 'models/vote'
require_relative 'models/user'
env_index = ARGV.index("-e")
env_arg = ARGV[env_index + 1] if env_index
......@@ -103,11 +105,12 @@ put '/api/v1/votes/comments/:comment_id/users/:user_id' do |comment_id, user_id|
if comment.nil?
error 400, {:error => "invalid comment id"}.to_json
else
vote = Vote.create_or_update :user_id => user_id, :comment_id => comment_id, :value => params["value"]
if vote
if %w[up down].include? params["value"]
user = User.find_or_create_by_id(user_id)
vote = user.vote(comment, { :direction => (params["value"] == "up" ? :up : :down ), :exclusive => :true})
vote.to_json
else
error 400, vote.errors.to_json
error 400, {:error => "value must be up or down"}
end
end
end
......@@ -115,12 +118,13 @@ end
# undo the vote on the comment by the user
delete '/api/v1/votes/comments/:comment_id/users/:user_id' do |comment_id, user_id|
vote = Vote.find_by_comment_id_and_user_id(comment_id, user_id)
if vote.nil?
error 400, {:error => "vote does not exist"}.to_json
else
vote.destroy
user = User.find_by_id(user_id.to_i)
comment = Comment.find_by_id(comment_id)
if user and comment and not comment.is_root?
vote = user.unvote_for(comment)
vote.to_json
else
error 400, {:error => "invalid user or comment id"}
end
end
......
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
end
end
def self.down
drop_table :users
end
end
class CreateVotes < ActiveRecord::Migration
def self.up
create_table :votes do |t|
t.integer :user_id
t.integer :comment_id
t.string :value
create_table :votes, :force => true do |t|
t.boolean :vote, :default => false
t.references :voteable, :polymorphic => true, :null => false
t.references :voter, :polymorphic => true
t.timestamps
end
add_index :votes, :comment_id
add_index :votes, :user_id
add_index :votes, [:comment_id, :user_id]
add_index :votes, [:voter_id, :voter_type]
add_index :votes, [:voteable_id, :voteable_type]
add_index :votes, [:voter_id, :voter_type, :voteable_id, :voteable_type], :unique => true, :name => 'fk_one_vote_per_user_per_entity'
end
def self.down
drop_table :votes
end
end
require 'active_record'
require 'ancestry'
require 'thumbs_up'
class Comment < ActiveRecord::Base
......@@ -7,10 +8,10 @@ class Comment < ActiveRecord::Base
has_ancestry
has_many :votes
belongs_to :comment_thread
acts_as_voteable
validates_presence_of :body, :unless => :is_root?
validates_presence_of :user_id, :unless => :is_root?
validates_presence_of :course_id, :unless => :is_root?
......@@ -25,7 +26,7 @@ class Comment < ActiveRecord::Base
end
def to_hash
attributes.merge(:votes => {:up => Vote.comment_id(id).up.count, :down => Vote.comment_id(id).down.count})
attributes.merge(:votes => {:up => votes_for, :down => votes_against})
end
def to_json
......
require 'active_record'
require 'thumbs_up'
class User < ActiveRecord::Base
acts_as_voter
end
require 'active_record'
# Adapted from "Service-Oriented Design with Ruby and Rails"
class Vote < ActiveRecord::Base
attr_accessible :value, :user_id, :comment_id
belongs_to :comment
scope :for_voter, lambda { |*args| where(["voter_id = ? AND voter_type = ?", args.first.id, args.first.class.base_class.name]) }
scope :for_voteable, lambda { |*args| where(["voteable_id = ? AND voteable_type = ?", args.first.id, args.first.class.base_class.name]) }
scope :recent, lambda { |*args| where(["created_at > ?", (args.first || 2.weeks.ago)]) }
scope :descending, order("created_at DESC")
validates_inclusion_of :value, :in => %w{up down}
validates_uniqueness_of :user_id, :scope => :comment_id
validates_presence_of :comment_id, :user_id
belongs_to :voteable, :polymorphic => true
belongs_to :voter, :polymorphic => true
scope :up, :conditions => ["value = ?", "up"]
scope :down, :conditions => ["value = ?", "down"]
scope :user_id, lambda {|user_id| {:conditions => ["user_id = ?", user_id]}}
scope :comment_id, lambda {|comment_id| {:conditions => ["comment_id = ?", comment_id]}}
attr_accessible :vote, :voter, :voteable
def self.create_or_update(attributes)
vote = Vote.find_by_comment_id_and_user_id(attributes[:comment_id], attributes[:user_id])
if vote
vote.value = attributes[:value]
vote.save
vote
else
Vote.create(attributes)
end
end
# Comment out the line below to allow multiple votes per user.
validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
end
......@@ -69,13 +69,14 @@ describe "app" do
comment << (comment_thread.root_comments.create :body => "top comment", :title => "top 0", :user_id => 1, :course_id => 1, :comment_thread_id => comment_thread.id)
sub_comment << (comment[0].children.create :body => "comment body", :title => "comment title 0", :user_id => 1, :course_id => 1, :comment_thread_id => comment_thread.id)
sub_comment << (comment[0].children.create :body => "comment body", :title => "comment title 1", :user_id => 1, :course_id => 1, :comment_thread_id => comment_thread.id)
Vote.create! :value => "up", :comment_id => comment[0].id, :user_id => 1
Vote.create! :value => "up", :comment_id => comment[0].id, :user_id => 2
Vote.create! :value => "up", :comment_id => comment[0].id, :user_id => 3
Vote.create! :value => "up", :comment_id => comment[0].id, :user_id => 4
Vote.create! :value => "down", :comment_id => comment[0].id, :user_id => 5
Vote.create! :value => "down", :comment_id => comment[0].id, :user_id => 6
Vote.create! :value => "down", :comment_id => comment[0].id, :user_id => 7
(1..4).each do |id|
user = User.find_or_create_by_id(id)
user.vote_for(comment[0])
end
(5..7).each do |id|
user = User.find_or_create_by_id(id)
user.vote_against(comment[0])
end
get "/api/v1/commentables/questions/1/comments"
last_response.should be_ok
comments = Yajl::Parser.parse last_response.body
......@@ -196,16 +197,18 @@ describe "app" do
comment = CommentThread.first.root_comments.create :body => "top comment", :title => "top", :user_id => 1, :course_id => 1
comment.comment_thread = comment_thread
comment.save!
Vote.delete_all
end
it "votes up on a comment" do
comment = CommentThread.first.comments.first
put "/api/v1/votes/comments/#{comment.id}/users/1", :value => "up"
last_response.should be_ok
vote = Vote.first
puts vote
vote.should_not be_nil
vote.user_id.should == 1
vote.comment_id.should == comment.id
vote.value.should == "up"
vote.voter_id.should == 1
vote.voteable_id.should == comment.id
vote.vote.should be_true
end
it "votes down on a comment" do
comment = CommentThread.first.comments.first
......@@ -213,9 +216,10 @@ describe "app" do
last_response.should be_ok
vote = Vote.first
vote.should_not be_nil
vote.user_id.should == 1
vote.comment_id.should == comment.id
vote.value.should == "down"
vote.voter_id.should == 1
vote.voteable_id.should == comment.id
vote.vote.should be_false
end
it "rejects invalid vote value" do
comment = CommentThread.first.comments.first
......@@ -229,10 +233,11 @@ describe "app" do
end
it "change vote on comment" do
comment = CommentThread.first.comments.first
Vote.create! :value => "up", :user_id => 1, :comment_id => comment.id
user = User.find_or_create_by_id(1)
user.vote_for(comment)
put "/api/v1/votes/comments/#{comment.id}/users/1", :value => "down"
last_response.should be_ok
Vote.first.value.should == "down"
Vote.first.vote.should be_false
end
end
describe "DELETE on /api/v1/votes/comments/:comment_id/users/:user_id" do
......@@ -242,15 +247,16 @@ describe "app" do
end
it "deletes vote" do
comment = CommentThread.first.comments.first
Vote.create! :value => "up", :user_id => 1, :comment_id => comment.id
user = User.find_or_create_by_id(1)
user.vote_for(comment)
delete "/api/v1/votes/comments/#{comment.id}/users/1"
last_response.should be_ok
Vote.count.should == 0
end
it "returns 400 for nonexisted vote" do
it "does nothing for nonexisted vote" do
comment = CommentThread.first.comments.first
delete "/api/v1/votes/comments/#{comment.id}/users/1"
last_response.status.should == 400
last_response.should be_ok
end
end
end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment