From 9f353c32f4107f1f17c9e3064bb65078e7f7af58 Mon Sep 17 00:00:00 2001 From: albert Date: Mon, 15 Feb 2010 17:45:09 -0500 Subject: [PATCH] added post voting --- app/models/comment.rb | 6 +-- app/models/comment_vote.rb | 2 + app/models/post.rb | 24 ++++++++- app/models/post_vote.rb | 5 ++ app/models/user.rb | 8 +-- db/development_structure.sql | 51 ++++++++++++++++++- .../20100215223541_create_post_votes.rb | 13 +++++ test/unit/comment_test.rb | 2 +- test/unit/comment_vote_test.rb | 8 --- test/unit/post_test.rb | 12 +++++ 10 files changed, 112 insertions(+), 19 deletions(-) create mode 100644 app/models/post_vote.rb create mode 100644 db/migrate/20100215223541_create_post_votes.rb delete mode 100644 test/unit/comment_vote_test.rb diff --git a/app/models/comment.rb b/app/models/comment.rb index 1ec6ee165..78bea1844 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,6 +1,4 @@ -class Comment < ActiveRecord::Base - class VotingError < Exception ; end - +class Comment < ActiveRecord::Base validates_format_of :body, :with => /\S/, :message => 'has no content' belongs_to :post belongs_to :creator, :class_name => "User" @@ -35,7 +33,7 @@ class Comment < ActiveRecord::Base votes.create(:user_id => user.id) else - raise VotingError.new("You have already voted for this comment") + raise CommentVote::Error.new("You have already voted for this comment") end end end diff --git a/app/models/comment_vote.rb b/app/models/comment_vote.rb index b9197a470..7d30fc284 100644 --- a/app/models/comment_vote.rb +++ b/app/models/comment_vote.rb @@ -1,4 +1,6 @@ class CommentVote < ActiveRecord::Base + class Error < Exception ; end + belongs_to :comment belongs_to :user diff --git a/app/models/post.rb b/app/models/post.rb index fcc42968c..53a20ce39 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -12,6 +12,7 @@ class Post < ActiveRecord::Base has_one :unapproval, :dependent => :destroy has_one :upload, :dependent => :destroy has_many :versions, :class_name => "PostVersion", :dependent => :destroy + has_many :votes, :class_name => "PostVote", :dependent => :destroy attr_accessible :source, :rating, :tag_string, :old_tag_string module FileMethods @@ -140,7 +141,7 @@ class Post < ActiveRecord::Base self.source = version.source self.rating = version.rating self.tag_string = version.tag_string - save + save! end end @@ -473,6 +474,26 @@ class Post < ActiveRecord::Base end end + module VoteMethods + def can_be_voted_by?(user) + !votes.exists?(["user_id = ?", user.id]) + end + + def vote!(user, is_positive) + if can_be_voted_by?(user) + if is_positive + increment!(:score) + else + decrement!(:score) + end + + votes.create(:user_id => user.id) + else + raise PostVote::Error.new("You have already voted for this comment") + end + end + end + include FileMethods include ImageMethods include ModerationMethods @@ -483,6 +504,7 @@ class Post < ActiveRecord::Base include UploaderMethods include PoolMethods extend SearchMethods + include VoteMethods def reload(options = nil) super diff --git a/app/models/post_vote.rb b/app/models/post_vote.rb new file mode 100644 index 000000000..bafbcce27 --- /dev/null +++ b/app/models/post_vote.rb @@ -0,0 +1,5 @@ +class PostVote < ActiveRecord::Base + class Error < Exception ; end + + belongs_to :post +end diff --git a/app/models/user.rb b/app/models/user.rb index 38294fdc7..248b1786c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -14,10 +14,6 @@ class User < ActiveRecord::Base after_save :update_cache scope :named, lambda {|name| where(["lower(name) = ?", name])} - def can_update?(object, foreign_key = :user_id) - is_moderator? || is_admin? || object.__send__(foreign_key) == id - end - module NameMethods module ClassMethods def find_name(user_id) @@ -100,5 +96,9 @@ class User < ActiveRecord::Base include PasswordMethods extend AuthenticationMethods include FavoriteMethods + + def can_update?(object, foreign_key = :user_id) + is_moderator? || is_admin? || object.__send__(foreign_key) == id + end end diff --git a/db/development_structure.sql b/db/development_structure.sql index d19a9ad16..c4aa790ef 100644 --- a/db/development_structure.sql +++ b/db/development_structure.sql @@ -655,6 +655,38 @@ CREATE SEQUENCE post_versions_id_seq ALTER SEQUENCE post_versions_id_seq OWNED BY post_versions.id; +-- +-- Name: post_votes; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE post_votes ( + id integer NOT NULL, + post_id integer NOT NULL, + user_id integer NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: post_votes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE post_votes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: post_votes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE post_votes_id_seq OWNED BY post_votes.id; + + -- -- Name: posts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -1145,6 +1177,13 @@ ALTER TABLE pools ALTER COLUMN id SET DEFAULT nextval('pools_id_seq'::regclass); ALTER TABLE post_versions ALTER COLUMN id SET DEFAULT nextval('post_versions_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE post_votes ALTER COLUMN id SET DEFAULT nextval('post_votes_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -1352,6 +1391,14 @@ ALTER TABLE ONLY post_versions ADD CONSTRAINT post_versions_pkey PRIMARY KEY (id); +-- +-- Name: post_votes_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY post_votes + ADD CONSTRAINT post_votes_pkey PRIMARY KEY (id); + + -- -- Name: posts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -1913,4 +1960,6 @@ INSERT INTO schema_migrations (version) VALUES ('20100214080605'); INSERT INTO schema_migrations (version) VALUES ('20100215182234'); -INSERT INTO schema_migrations (version) VALUES ('20100215213756'); \ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('20100215213756'); + +INSERT INTO schema_migrations (version) VALUES ('20100215223541'); \ No newline at end of file diff --git a/db/migrate/20100215223541_create_post_votes.rb b/db/migrate/20100215223541_create_post_votes.rb new file mode 100644 index 000000000..9431ecdd2 --- /dev/null +++ b/db/migrate/20100215223541_create_post_votes.rb @@ -0,0 +1,13 @@ +class CreatePostVotes < ActiveRecord::Migration + def self.up + create_table :post_votes do |t| + t.column :post_id, :integer, :null => false + t.column :user_id, :integer, :null => false + t.timestamps + end + end + + def self.down + drop_table :post_votes + end +end diff --git a/test/unit/comment_test.rb b/test/unit/comment_test.rb index 86380482e..3396934ed 100644 --- a/test/unit/comment_test.rb +++ b/test/unit/comment_test.rb @@ -38,7 +38,7 @@ class CommentTest < ActiveSupport::TestCase post = Factory.create(:post) c1 = Factory.create(:comment, :post => post) assert_nothing_raised {c1.vote!(user, true)} - assert_raise(Comment::VotingError) {c1.vote!(user, true)} + assert_raise(CommentVote::Error) {c1.vote!(user, true)} assert_equal(1, CommentVote.count) c2 = Factory.create(:comment, :post => post) diff --git a/test/unit/comment_vote_test.rb b/test/unit/comment_vote_test.rb deleted file mode 100644 index b8e167410..000000000 --- a/test/unit/comment_vote_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'test_helper' - -class CommentVoteTest < ActiveSupport::TestCase - # Replace this with your real tests. - test "the truth" do - assert true - end -end diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb index a2367be87..292d356c8 100644 --- a/test/unit/post_test.rb +++ b/test/unit/post_test.rb @@ -405,4 +405,16 @@ class PostTest < ActiveSupport::TestCase assert_equal(post3.id, relation.first.id) end end + + context "Voting on a post" do + should "not allow duplicate votes" do + user = Factory.create(:user) + post = Factory.create(:post) + assert_nothing_raised {post.vote!(user, true)} + assert_raise(PostVote::Error) {post.vote!(user, true)} + post.reload + assert_equal(1, PostVote.count) + assert_equal(1, post.score) + end + end end