vote_fu 0.0.11 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +78 -0
- data/README.md +265 -0
- data/app/assets/stylesheets/vote_fu/votes.css +391 -0
- data/app/channels/vote_fu/application_cable/channel.rb +8 -0
- data/app/channels/vote_fu/application_cable/connection.rb +39 -0
- data/app/channels/vote_fu/votes_channel.rb +99 -0
- data/app/components/vote_fu/like_button_component.rb +136 -0
- data/app/components/vote_fu/reaction_bar_component.rb +208 -0
- data/app/components/vote_fu/star_rating_component.rb +199 -0
- data/app/components/vote_fu/vote_widget_component.rb +181 -0
- data/app/controllers/vote_fu/application_controller.rb +49 -0
- data/app/controllers/vote_fu/votes_controller.rb +223 -0
- data/app/helpers/vote_fu/votes_helper.rb +176 -0
- data/app/javascript/vote_fu/channels/consumer.js +3 -0
- data/app/javascript/vote_fu/channels/index.js +2 -0
- data/app/javascript/vote_fu/channels/votes_channel.js +93 -0
- data/app/javascript/vote_fu/controllers/application.js +9 -0
- data/app/javascript/vote_fu/controllers/index.js +9 -0
- data/app/javascript/vote_fu/controllers/vote_fu_controller.js +148 -0
- data/app/javascript/vote_fu/controllers/vote_fu_reactions_controller.js +92 -0
- data/app/javascript/vote_fu/controllers/vote_fu_stars_controller.js +77 -0
- data/app/models/vote_fu/application_record.rb +7 -0
- data/app/models/vote_fu/vote.rb +90 -0
- data/app/views/vote_fu/votes/_count.html.erb +29 -0
- data/app/views/vote_fu/votes/_downvote_button.html.erb +40 -0
- data/app/views/vote_fu/votes/_error.html.erb +9 -0
- data/app/views/vote_fu/votes/_like_button.html.erb +67 -0
- data/app/views/vote_fu/votes/_upvote_button.html.erb +40 -0
- data/app/views/vote_fu/votes/_widget.html.erb +85 -0
- data/config/importmap.rb +6 -0
- data/config/routes.rb +9 -0
- data/lib/generators/vote_fu/install/install_generator.rb +56 -0
- data/lib/generators/vote_fu/install/templates/initializer.rb +42 -0
- data/lib/generators/vote_fu/install/templates/migration.rb.erb +41 -0
- data/lib/generators/vote_fu/migration/migration_generator.rb +29 -0
- data/lib/generators/vote_fu/migration/templates/create_vote_fu_votes.rb.erb +40 -0
- data/lib/vote_fu/algorithms/hacker_news.rb +54 -0
- data/lib/vote_fu/algorithms/reddit_hot.rb +55 -0
- data/lib/vote_fu/algorithms/wilson_score.rb +69 -0
- data/lib/vote_fu/concerns/karmatic.rb +320 -0
- data/lib/vote_fu/concerns/voteable.rb +291 -0
- data/lib/vote_fu/concerns/voter.rb +275 -0
- data/lib/vote_fu/configuration.rb +53 -0
- data/lib/vote_fu/engine.rb +54 -0
- data/lib/vote_fu/errors.rb +34 -0
- data/lib/vote_fu/version.rb +5 -0
- data/lib/vote_fu.rb +22 -9
- metadata +215 -63
- data/CHANGELOG.markdown +0 -31
- data/README.markdown +0 -220
- data/examples/routes.rb +0 -7
- data/examples/users_controller.rb +0 -76
- data/examples/voteable.html.erb +0 -8
- data/examples/voteable.rb +0 -10
- data/examples/voteables_controller.rb +0 -117
- data/examples/votes/_voteable_vote.html.erb +0 -23
- data/examples/votes/create.rjs +0 -1
- data/examples/votes_controller.rb +0 -110
- data/generators/vote_fu/templates/migration.rb +0 -21
- data/generators/vote_fu/vote_fu_generator.rb +0 -8
- data/init.rb +0 -1
- data/lib/acts_as_voteable.rb +0 -114
- data/lib/acts_as_voter.rb +0 -75
- data/lib/controllers/votes_controller.rb +0 -96
- data/lib/has_karma.rb +0 -68
- data/lib/models/vote.rb +0 -17
- data/rails/init.rb +0 -10
- data/test/vote_fu_test.rb +0 -8
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# This example controller assumes you are using the User class from restful_authentication
|
|
2
|
-
# and a nested voteable resource. See routes.rb
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class VoteablesController < ApplicationController
|
|
6
|
-
|
|
7
|
-
before_filter :find_user
|
|
8
|
-
before_filter :login_required, :only => [:new, :edit, :destroy, :create, :update]
|
|
9
|
-
before_filter :must_own_voteable, :only => [:edit, :destroy, :update]
|
|
10
|
-
|
|
11
|
-
# GET /users/:id/voteables
|
|
12
|
-
# GET /users/:id/voteables.xml
|
|
13
|
-
def index
|
|
14
|
-
@voteable = Voteable.descending
|
|
15
|
-
|
|
16
|
-
respond_to do |format|
|
|
17
|
-
format.html # index.html.erb
|
|
18
|
-
format.xml { render :xml => @voteables }
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# GET /users/:id/voteables/1
|
|
23
|
-
# GET /users/:id/voteables/1.xml
|
|
24
|
-
def show
|
|
25
|
-
@voteable = Voteable.find(params[:id])
|
|
26
|
-
|
|
27
|
-
respond_to do |format|
|
|
28
|
-
format.html # show.html.erb
|
|
29
|
-
format.xml { render :xml => @voteable }
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# GET /users/:id/voteables/new
|
|
34
|
-
# GET /users/:id/voteables/new.xml
|
|
35
|
-
def new
|
|
36
|
-
@voteable = Voteable.new
|
|
37
|
-
|
|
38
|
-
respond_to do |format|
|
|
39
|
-
format.html # new.html.erb
|
|
40
|
-
format.xml { render :xml => @voteable }
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# GET /users/:id/voteables/1/edit
|
|
45
|
-
def edit
|
|
46
|
-
@voteable ||= Voteable.find(params[:id])
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# POST /users/:id/voteables
|
|
50
|
-
# POST /users/:id/voteables.xml
|
|
51
|
-
def create
|
|
52
|
-
@voteable = Voteable.new(params[:voteable])
|
|
53
|
-
@voteable.user = current_user
|
|
54
|
-
|
|
55
|
-
respond_to do |format|
|
|
56
|
-
if @voteable.save
|
|
57
|
-
flash[:notice] = 'Voteable was successfully saved.'
|
|
58
|
-
format.html { redirect_to([@user, @voteable]) }
|
|
59
|
-
format.xml { render :xml => @voteable, :status => :created, :location => @voteable }
|
|
60
|
-
else
|
|
61
|
-
format.html { render :action => "new" }
|
|
62
|
-
format.xml { render :xml => @voteable.errors, :status => :unprocessable_entity }
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# PUT /users/:id/voteable/1
|
|
68
|
-
# PUT /users/:id/voteable/1.xml
|
|
69
|
-
def update
|
|
70
|
-
@voteable = Voteable.find(params[:id])
|
|
71
|
-
|
|
72
|
-
respond_to do |format|
|
|
73
|
-
if @quote.update_attributes(params[:voteable])
|
|
74
|
-
flash[:notice] = 'Voteable was successfully updated.'
|
|
75
|
-
format.html { redirect_to([@user, @voteable]) }
|
|
76
|
-
format.xml { head :ok }
|
|
77
|
-
else
|
|
78
|
-
format.html { render :action => "edit" }
|
|
79
|
-
format.xml { render :xml => @voteable.errors, :status => :unprocessable_entity }
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# DELETE /users/:id/voteable/1
|
|
85
|
-
# DELETE /users/:id/voteable/1.xml
|
|
86
|
-
def destroy
|
|
87
|
-
@voteable = Voteable.find(params[:id])
|
|
88
|
-
@voteable.destroy
|
|
89
|
-
|
|
90
|
-
respond_to do |format|
|
|
91
|
-
format.html { redirect_to(user_voteables_url) }
|
|
92
|
-
format.xml { head :ok }
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
private
|
|
97
|
-
def find_user
|
|
98
|
-
@user = User.find(params[:user_id])
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def must_own_voteable
|
|
102
|
-
@voteable ||= Voteable.find(params[:id])
|
|
103
|
-
@voteable.user == current_user || ownership_violation
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def ownership_violation
|
|
107
|
-
respond_to do |format|
|
|
108
|
-
flash[:notice] = 'You cannot edit or delete voteable that you do not own!'
|
|
109
|
-
format.html do
|
|
110
|
-
redirect_to user_path(current_user)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<%
|
|
2
|
-
# You can't vote if it is your quote,
|
|
3
|
-
# you are not logged in,
|
|
4
|
-
# or you have already voted on this item
|
|
5
|
-
|
|
6
|
-
unless quote.user == current_user ||
|
|
7
|
-
!logged_in? ||
|
|
8
|
-
current_user.voted_on?(@voteable)
|
|
9
|
-
%>
|
|
10
|
-
|
|
11
|
-
<%= link_to_remote "Up",
|
|
12
|
-
:url => user_voteable_votes_path(voteable.user, voteable, :vote => :true, :format => :rjs),
|
|
13
|
-
:method => :post
|
|
14
|
-
%>
|
|
15
|
-
/
|
|
16
|
-
<%= link_to_remote "Down",
|
|
17
|
-
:url => user_voteable_votes_path(voteable.user, voteable, :vote => :false, :format => :rjs),
|
|
18
|
-
:method => :post
|
|
19
|
-
%>
|
|
20
|
-
|
|
21
|
-
<% end %>
|
|
22
|
-
|
|
23
|
-
Votes: <%= voteable.votes_for - voteable.votes_against %>
|
data/examples/votes/create.rjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
page.replace_html "votes_#{@voteable.id}", :partial => "voteable_vote", :locals => {:voteable => @voteable}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# An example controller for "votes" that are nested resources under users. See examples/routes.rb
|
|
2
|
-
|
|
3
|
-
class VotesController < ApplicationController
|
|
4
|
-
|
|
5
|
-
# First, figure out our nested scope. User or Voteable?
|
|
6
|
-
before_filter :find_votes_for_my_scope, :only => [:index]
|
|
7
|
-
|
|
8
|
-
before_filter :login_required, :only => [:new, :edit, :destroy, :create, :update]
|
|
9
|
-
before_filter :must_own_vote, :only => [:edit, :destroy, :update]
|
|
10
|
-
before_filter :not_allowed, :only => [:edit, :update, :new]
|
|
11
|
-
|
|
12
|
-
# GET /users/:user_id/votes/
|
|
13
|
-
# GET /users/:user_id/votes.xml
|
|
14
|
-
# GET /users/:user_id/voteables/:voteable_id/votes/
|
|
15
|
-
# GET /users/:user_id/voteables/:voteable_id/votes.xml
|
|
16
|
-
def index
|
|
17
|
-
respond_to do |format|
|
|
18
|
-
format.html # index.html.erb
|
|
19
|
-
format.xml { render :xml => @votes }
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# GET /users/:user_id/votes/1
|
|
24
|
-
# GET /users/:user_id/votes/1.xml
|
|
25
|
-
# GET /users/:user_id/voteables/:voteable_id/votes/1
|
|
26
|
-
# GET /users/:user_id/voteables/:voteable_id/1.xml
|
|
27
|
-
def show
|
|
28
|
-
@voteable = Vote.find(params[:id])
|
|
29
|
-
|
|
30
|
-
respond_to do |format|
|
|
31
|
-
format.html # show.html.erb
|
|
32
|
-
format.xml { render :xml => @vote }
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# GET /users/:id/votes/new
|
|
37
|
-
# GET /users/:id/votes/new.xml
|
|
38
|
-
# GET /users/:id/votes/new
|
|
39
|
-
# GET /users/:id/votes/new.xml
|
|
40
|
-
def new
|
|
41
|
-
# Not generally used. Most people want to vote via AJAX calls.
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# GET /users/:id/votes/1/edit
|
|
45
|
-
def edit
|
|
46
|
-
# Not generally used. Most people don't want to allow editing of votes.
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# POST /users/:user_id/voteables/:voteable_id/votes
|
|
50
|
-
# POST /users/:user_id/voteables/:voteable_id/votes.xml
|
|
51
|
-
def create
|
|
52
|
-
@voteable = Voteable.find(params[:quote_id])
|
|
53
|
-
|
|
54
|
-
respond_to do |format|
|
|
55
|
-
if current_user.vote(@voteable, params[:vote])
|
|
56
|
-
format.rjs { render :action => "create", :vote => @vote }
|
|
57
|
-
format.html { redirect_to([@voteable.user, @voteable]) }
|
|
58
|
-
format.xml { render :xml => @voteable, :status => :created, :location => @voteable }
|
|
59
|
-
else
|
|
60
|
-
format.rjs { render :action => "error" }
|
|
61
|
-
format.html { render :action => "new" }
|
|
62
|
-
format.xml { render :xml => @vote.errors, :status => :unprocessable_entity }
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# PUT /users/:id/votes/1
|
|
68
|
-
# PUT /users/:id/votes/1.xml
|
|
69
|
-
def update
|
|
70
|
-
# Not generally used
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# DELETE /users/:id/votes/1
|
|
74
|
-
# DELETE /users/:id/votes/1.xml
|
|
75
|
-
def destroy
|
|
76
|
-
@vote = Vote.find(params[:id])
|
|
77
|
-
@vote.destroy
|
|
78
|
-
|
|
79
|
-
respond_to do |format|
|
|
80
|
-
format.html { redirect_to(user_votes_url) }
|
|
81
|
-
format.xml { head :ok }
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
def find_votes_for_my_scope
|
|
87
|
-
if params[:voteable_id]
|
|
88
|
-
@votes = Vote.for_voteable(Voteable.find(params[:voteable_id])).descending
|
|
89
|
-
elsif params[:user_id]
|
|
90
|
-
@votes = Vote.for_voter(User.find(params[:user_id])).descending
|
|
91
|
-
else
|
|
92
|
-
@votes = []
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def must_own_vote
|
|
97
|
-
@vote ||= Vote.find(params[:id])
|
|
98
|
-
@vote.user == current_user || ownership_violation
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def ownership_violation
|
|
102
|
-
respond_to do |format|
|
|
103
|
-
flash[:notice] = 'You cannot edit or delete votes that you do not own!'
|
|
104
|
-
format.html do
|
|
105
|
-
redirect_to user_path(current_user)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
class VoteFuMigration < ActiveRecord::Migration
|
|
2
|
-
def self.up
|
|
3
|
-
create_table :votes, :force => true do |t|
|
|
4
|
-
t.boolean :vote, :default => false
|
|
5
|
-
t.references :voteable, :polymorphic => true, :null => false
|
|
6
|
-
t.references :voter, :polymorphic => true
|
|
7
|
-
t.timestamps
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
add_index :votes, ["voter_id", "voter_type"], :name => "fk_voters"
|
|
11
|
-
add_index :votes, ["voteable_id", "voteable_type"], :name => "fk_voteables"
|
|
12
|
-
|
|
13
|
-
# If you want to enfore "One Person, One Vote" rules in the database, uncomment the index below
|
|
14
|
-
# add_index :votes, ["voter_id", "voter_type", "voteable_id", "voteable_type"], :unique => true, :name => "uniq_one_vote_only"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def self.down
|
|
18
|
-
drop_table :votes
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
end
|
data/init.rb
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require 'vote_fu'
|
data/lib/acts_as_voteable.rb
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# ActsAsVoteable
|
|
2
|
-
module Juixe
|
|
3
|
-
module Acts #:nodoc:
|
|
4
|
-
module Voteable #:nodoc:
|
|
5
|
-
|
|
6
|
-
def self.included(base)
|
|
7
|
-
base.extend ClassMethods
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
module ClassMethods
|
|
11
|
-
def acts_as_voteable
|
|
12
|
-
has_many :votes, :as => :voteable, :dependent => :nullify
|
|
13
|
-
|
|
14
|
-
include Juixe::Acts::Voteable::InstanceMethods
|
|
15
|
-
extend Juixe::Acts::Voteable::SingletonMethods
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# This module contains class methods
|
|
20
|
-
module SingletonMethods
|
|
21
|
-
|
|
22
|
-
# Calculate the vote counts for all voteables of my type.
|
|
23
|
-
def tally(options = {})
|
|
24
|
-
find(:all, options_for_tally(options.merge({:order =>"count DESC" })))
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
#
|
|
28
|
-
# Options:
|
|
29
|
-
# :start_at - Restrict the votes to those created after a certain time
|
|
30
|
-
# :end_at - Restrict the votes to those created before a certain time
|
|
31
|
-
# :conditions - A piece of SQL conditions to add to the query
|
|
32
|
-
# :limit - The maximum number of voteables to return
|
|
33
|
-
# :order - A piece of SQL to order by. Eg 'votes.count desc' or 'voteable.created_at desc'
|
|
34
|
-
# :at_least - Item must have at least X votes
|
|
35
|
-
# :at_most - Item may not have more than X votes
|
|
36
|
-
def options_for_tally (options = {})
|
|
37
|
-
options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit
|
|
38
|
-
|
|
39
|
-
scope = scope(:find)
|
|
40
|
-
start_at = sanitize_sql(["#{Vote.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
|
|
41
|
-
end_at = sanitize_sql(["#{Vote.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
|
|
42
|
-
|
|
43
|
-
type_and_context = "#{Vote.table_name}.voteable_type = #{quote_value(base_class.name)}"
|
|
44
|
-
|
|
45
|
-
conditions = [
|
|
46
|
-
type_and_context,
|
|
47
|
-
options[:conditions],
|
|
48
|
-
start_at,
|
|
49
|
-
end_at
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
conditions = conditions.compact.join(' AND ')
|
|
53
|
-
conditions = merge_conditions(conditions, scope[:conditions]) if scope
|
|
54
|
-
|
|
55
|
-
joins = ["LEFT OUTER JOIN #{Vote.table_name} ON #{table_name}.#{primary_key} = #{Vote.table_name}.voteable_id"]
|
|
56
|
-
joins << scope[:joins] if scope && scope[:joins]
|
|
57
|
-
at_least = sanitize_sql(["COUNT(#{Vote.table_name}.id) >= ?", options.delete(:at_least)]) if options[:at_least]
|
|
58
|
-
at_most = sanitize_sql(["COUNT(#{Vote.table_name}.id) <= ?", options.delete(:at_most)]) if options[:at_most]
|
|
59
|
-
having = [at_least, at_most].compact.join(' AND ')
|
|
60
|
-
group_by = "#{Vote.table_name}.voteable_id HAVING COUNT(#{Vote.table_name}.id) > 0"
|
|
61
|
-
group_by << " AND #{having}" unless having.blank?
|
|
62
|
-
|
|
63
|
-
{ :select => "#{table_name}.*, COUNT(#{Vote.table_name}.id) AS count",
|
|
64
|
-
:joins => joins.join(" "),
|
|
65
|
-
:conditions => conditions,
|
|
66
|
-
:group => group_by
|
|
67
|
-
}.update(options)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# This module contains instance methods
|
|
72
|
-
module InstanceMethods
|
|
73
|
-
def votes_for
|
|
74
|
-
Vote.count(:all, :conditions => [
|
|
75
|
-
"voteable_id = ? AND voteable_type = ? AND vote = ?",
|
|
76
|
-
id, self.class.name, true
|
|
77
|
-
])
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def votes_against
|
|
81
|
-
Vote.count(:all, :conditions => [
|
|
82
|
-
"voteable_id = ? AND voteable_type = ? AND vote = ?",
|
|
83
|
-
id, self.class.name, false
|
|
84
|
-
])
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Same as voteable.votes.size
|
|
88
|
-
def votes_count
|
|
89
|
-
self.votes.size
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def voters_who_voted
|
|
93
|
-
voters = []
|
|
94
|
-
self.votes.each { |v|
|
|
95
|
-
voters << v.voter
|
|
96
|
-
}
|
|
97
|
-
voters
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def voted_by?(voter)
|
|
101
|
-
rtn = false
|
|
102
|
-
if voter
|
|
103
|
-
self.votes.each { |v|
|
|
104
|
-
rtn = true if (voter.id == v.voter_id && voter.class.name == v.voter_type)
|
|
105
|
-
}
|
|
106
|
-
end
|
|
107
|
-
rtn
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
data/lib/acts_as_voter.rb
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# ActsAsVoter
|
|
2
|
-
module PeteOnRails
|
|
3
|
-
module Acts #:nodoc:
|
|
4
|
-
module Voter #:nodoc:
|
|
5
|
-
|
|
6
|
-
def self.included(base)
|
|
7
|
-
base.extend ClassMethods
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
module ClassMethods
|
|
11
|
-
def acts_as_voter
|
|
12
|
-
has_many :votes, :as => :voter, :dependent => :nullify # If a voting entity is deleted, keep the votes.
|
|
13
|
-
include PeteOnRails::Acts::Voter::InstanceMethods
|
|
14
|
-
extend PeteOnRails::Acts::Voter::SingletonMethods
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# This module contains class methods
|
|
19
|
-
module SingletonMethods
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# This module contains instance methods
|
|
23
|
-
module InstanceMethods
|
|
24
|
-
|
|
25
|
-
# Usage user.vote_count(true) # All +1 votes
|
|
26
|
-
# user.vote_count(false) # All -1 votes
|
|
27
|
-
# user.vote_count() # All votes
|
|
28
|
-
|
|
29
|
-
def vote_count(for_or_against = "all")
|
|
30
|
-
where = (for_or_against == "all") ?
|
|
31
|
-
["voter_id = ? AND voter_type = ?", id, self.class.name ] :
|
|
32
|
-
["voter_id = ? AND voter_type = ? AND vote = ?", id, self.class.name, for_or_against ]
|
|
33
|
-
|
|
34
|
-
Vote.count(:all, :conditions => where)
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def voted_for?(voteable)
|
|
39
|
-
0 < Vote.count(:all, :conditions => [
|
|
40
|
-
"voter_id = ? AND voter_type = ? AND vote = ? AND voteable_id = ? AND voteable_type = ?",
|
|
41
|
-
self.id, self.class.name, true, voteable.id, voteable.class.name
|
|
42
|
-
])
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def voted_against?(voteable)
|
|
46
|
-
0 < Vote.count(:all, :conditions => [
|
|
47
|
-
"voter_id = ? AND voter_type = ? AND vote = ? AND voteable_id = ? AND voteable_type = ?",
|
|
48
|
-
self.id, self.class.name, false, voteable.id, voteable.class.name
|
|
49
|
-
])
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def voted_on?(voteable)
|
|
53
|
-
0 < Vote.count(:all, :conditions => [
|
|
54
|
-
"voter_id = ? AND voter_type = ? AND voteable_id = ? AND voteable_type = ?",
|
|
55
|
-
self.id, self.class.name, voteable.id, voteable.class.name
|
|
56
|
-
])
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def vote_for(voteable)
|
|
60
|
-
self.vote(voteable, true)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def vote_against(voteable)
|
|
64
|
-
self.vote(voteable, false)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def vote(voteable, vote)
|
|
68
|
-
vote = Vote.new(:vote => vote, :voteable => voteable, :voter => self)
|
|
69
|
-
vote.save
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
class VotesController < ApplicationController
|
|
2
|
-
# First, figure out our nested scope. User or vote?
|
|
3
|
-
# before_filter :find_my_scope
|
|
4
|
-
|
|
5
|
-
# before_filter :find_user
|
|
6
|
-
|
|
7
|
-
# before_filter :login_required, :only => [:new, :edit, :destroy, :create, :update]
|
|
8
|
-
# before_filter :must_own_vote, :only => [:edit, :destroy, :update]
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# GET /votes/
|
|
12
|
-
# GET /votes.xml
|
|
13
|
-
def index
|
|
14
|
-
@votes = Vote.descending
|
|
15
|
-
|
|
16
|
-
respond_to do |format|
|
|
17
|
-
format.html # index.html.erb
|
|
18
|
-
format.xml { render :xml => @votes }
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# GET /votes/1
|
|
23
|
-
# GET /votes/1.xml
|
|
24
|
-
def show
|
|
25
|
-
@vote = Vote.find(params[:id])
|
|
26
|
-
|
|
27
|
-
respond_to do |format|
|
|
28
|
-
format.html # show.html.erb
|
|
29
|
-
format.xml { render :xml => @vote }
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# GET /votes/new
|
|
34
|
-
# GET /votes/new.xml
|
|
35
|
-
def new
|
|
36
|
-
@vote = Vote.new
|
|
37
|
-
|
|
38
|
-
respond_to do |format|
|
|
39
|
-
format.html # new.html.erb
|
|
40
|
-
format.xml { render :xml => @vote }
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# GET /votes/1/edit
|
|
45
|
-
def edit
|
|
46
|
-
@vote ||= Vote.find(params[:id])
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# POST /votes
|
|
50
|
-
# POST /votes.xml
|
|
51
|
-
def create
|
|
52
|
-
@vote = Vote.new(params[:vote])
|
|
53
|
-
@vote.user = current_user
|
|
54
|
-
|
|
55
|
-
respond_to do |format|
|
|
56
|
-
if @vote.save
|
|
57
|
-
flash[:notice] = 'Vote was successfully saved.'
|
|
58
|
-
format.html { redirect_to([@user, @vote]) }
|
|
59
|
-
format.xml { render :xml => @vote, :status => :created, :location => @vote }
|
|
60
|
-
else
|
|
61
|
-
format.html { render :action => "new" }
|
|
62
|
-
format.xml { render :xml => @vote.errors, :status => :unprocessable_entity }
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# PUT /votes/1
|
|
68
|
-
# PUT /votes/1.xml
|
|
69
|
-
def update
|
|
70
|
-
@vote = Vote.find(params[:id])
|
|
71
|
-
|
|
72
|
-
respond_to do |format|
|
|
73
|
-
if @vote.update_attributes(params[:vote])
|
|
74
|
-
flash[:notice] = 'Vote was successfully updated.'
|
|
75
|
-
format.html { redirect_to([@user, @vote]) }
|
|
76
|
-
format.xml { head :ok }
|
|
77
|
-
else
|
|
78
|
-
format.html { render :action => "edit" }
|
|
79
|
-
format.xml { render :xml => @vote.errors, :status => :unprocessable_entity }
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# DELETE /votes/1
|
|
85
|
-
# DELETE /votes/1.xml
|
|
86
|
-
def destroy
|
|
87
|
-
@vote = Vote.find(params[:id])
|
|
88
|
-
@vote.destroy
|
|
89
|
-
|
|
90
|
-
respond_to do |format|
|
|
91
|
-
format.html { redirect_to(user_votes_url) }
|
|
92
|
-
format.xml { head :ok }
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
end
|
data/lib/has_karma.rb
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Has Karma
|
|
2
|
-
|
|
3
|
-
module PeteOnRails
|
|
4
|
-
module VoteFu #:nodoc:
|
|
5
|
-
module Karma #:nodoc:
|
|
6
|
-
|
|
7
|
-
def self.included(base)
|
|
8
|
-
base.extend ClassMethods
|
|
9
|
-
class << base
|
|
10
|
-
attr_accessor :karmatic_objects
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
module ClassMethods
|
|
15
|
-
def has_karma(voteable_type)
|
|
16
|
-
self.class_eval <<-RUBY
|
|
17
|
-
def karma_voteable
|
|
18
|
-
#{voteable_type.to_s.classify}
|
|
19
|
-
end
|
|
20
|
-
RUBY
|
|
21
|
-
include PeteOnRails::VoteFu::Karma::InstanceMethods
|
|
22
|
-
extend PeteOnRails::VoteFu::Karma::SingletonMethods
|
|
23
|
-
if self.karmatic_objects.nil?
|
|
24
|
-
self.karmatic_objects = [eval(voteable_type.to_s.classify)]
|
|
25
|
-
else
|
|
26
|
-
self.karmatic_objects.push(eval(voteable_type.to_s.classify))
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# This module contains class methods
|
|
32
|
-
module SingletonMethods
|
|
33
|
-
|
|
34
|
-
## Not yet implemented. Don't use it!
|
|
35
|
-
# Find the most popular users
|
|
36
|
-
def find_most_karmic
|
|
37
|
-
find(:all)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# This module contains instance methods
|
|
43
|
-
module InstanceMethods
|
|
44
|
-
def karma(options = {})
|
|
45
|
-
#FIXME cannot have 2 models imapcting the karma simultaneously
|
|
46
|
-
# count the total number of votes on all of the voteable objects that are related to this object
|
|
47
|
-
#2009-01-30 GuillaumeNM The following line is not SQLite3 compatible, because boolean are stored as 'f' or 't', not '1', or '0'
|
|
48
|
-
#self.karma_voteable.sum(:vote, options_for_karma(options))
|
|
49
|
-
#self.karma_voteable.find(:all, options_for_karma(options)).length
|
|
50
|
-
karma_value = 0
|
|
51
|
-
self.class.karmatic_objects.each do |object|
|
|
52
|
-
karma_value += object.find(:all, options_for_karma(object, options)).length
|
|
53
|
-
end
|
|
54
|
-
return karma_value
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def options_for_karma (object, options = {})
|
|
58
|
-
#GuillaumeNM : 2009-01-30 Adding condition for SQLite3
|
|
59
|
-
conditions = ["u.id = ? AND vote = ?" , self[:id] , true]
|
|
60
|
-
joins = ["inner join votes v on #{object.table_name}.id = v.voteable_id", "inner join #{self.class.table_name} u on u.id = #{object.name.tableize}.#{self.class.name.foreign_key}"]
|
|
61
|
-
{ :joins => joins.join(" "), :conditions => conditions }.update(options)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
data/lib/models/vote.rb
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
class Vote < ActiveRecord::Base
|
|
2
|
-
|
|
3
|
-
named_scope :for_voter, lambda { |*args| {:conditions => ["voter_id = ? AND voter_type = ?", args.first.id, args.first.type.name]} }
|
|
4
|
-
named_scope :for_voteable, lambda { |*args| {:conditions => ["voteable_id = ? AND voteable_type = ?", args.first.id, args.first.type.name]} }
|
|
5
|
-
named_scope :recent, lambda { |*args| {:conditions => ["created_at > ?", (args.first || 2.weeks.ago).to_s(:db)]} }
|
|
6
|
-
named_scope :descending, :order => "created_at DESC"
|
|
7
|
-
|
|
8
|
-
# NOTE: Votes belong to the "voteable" interface, and also to voters
|
|
9
|
-
belongs_to :voteable, :polymorphic => true
|
|
10
|
-
belongs_to :voter, :polymorphic => true
|
|
11
|
-
|
|
12
|
-
attr_accessible :vote, :voter, :voteable
|
|
13
|
-
|
|
14
|
-
# Uncomment this to limit users to a single vote on each item.
|
|
15
|
-
# validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
|
|
16
|
-
|
|
17
|
-
end
|
data/rails/init.rb
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
RAILS_DEFAULT_LOGGER.info "** vote_fu: setting up load paths"
|
|
2
|
-
|
|
3
|
-
%w{ models controllers helpers }.each do |dir|
|
|
4
|
-
path = File.join(File.dirname(__FILE__) , 'lib', dir)
|
|
5
|
-
$LOAD_PATH << path
|
|
6
|
-
ActiveSupport::Dependencies.load_paths << path
|
|
7
|
-
ActiveSupport::Dependencies.load_once_paths.delete(path)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
require 'vote_fu'
|