adding cached vote stats fields and hall of famers

master
Coleman 2008-10-11 19:16:22 -05:00
parent e8e0cb98d0
commit 675e244864
8 changed files with 115 additions and 46 deletions

View File

@ -8,6 +8,8 @@ class Home < Application
end
def hall_of_fame
@top_oneness = Photo.find :all, :order => 'oneness DESC, id DESC', :limit => 10, :conditions => 'oneness > 0'
@top_voted = Photo.find :all, :order => 'votes_count DESC, id DESC', :limit => 10, :conditions => 'votes_count > 0'
render
end

View File

@ -8,52 +8,16 @@ class Photo < ActiveRecord::Base
before_create :validate_image_sanity
before_create :hashify_email
before_save :set_oneness
after_create :create_directories
before_destroy :destroy_directories
##
# Returns the biggest dimension of this model.
#
def max_dimension
if self.width > self.height
self.width
else
self.height
end
end
##
# Determines how 'oneable' this photo is. Should be cached in model later.
#
def oneness
os = one_votes
"%.1f%%" % (os.to_f / self.votes.size.to_f * 100.0)
end
##
# Abstraction to determine the number of positive votes on this photo. Should
# be replaced with a cached counter variable.
#
def one_votes
self.votes.count :id, :conditions => [ 'vote = ?', true ]
end
##
# Abstraction to determine the number of negative votes on this photo. Should
# be replaced with a cached counter variable.
#
def zero_votes
self.votes.size - self.one_votes
end
##
# Returns the path of the image relative to Merb's root.
#
def relative_directory
fkey = id.to_s[0,2]
skey = id.to_s[0,4]
"/photos/#{fkey}/#{skey}/#{id}"
"/photos/#{id.to_s[0,2]}/#{id.to_s[0,4]}/#{id}"
end
##
@ -163,4 +127,11 @@ class Photo < ActiveRecord::Base
email_hash = User.salted_string(email) unless email.to_s.empty?
true
end
##
# Regenerates the calculated value of oneness.
#
def set_oneness
self.oneness = (self.one_votes.to_f / self.votes_count.to_f * 100.0)
end
end

View File

@ -8,6 +8,9 @@ class Vote < ActiveRecord::Base
attr_protected :user_id
attr_protected :session_id
after_create :update_photo_stats
after_destroy :update_photo_stats
##
# Checks if this vote is anonymous, or not an authenticated User vote.
#
@ -54,7 +57,9 @@ class Vote < ActiveRecord::Base
end
##
# Does a quick find and collect on the cast votes so you can find a
# Does a quick find and collect on the cast votes so you can find all voted
# photo ids.
#
def self.voted_photo_ids(user)
c = if user.respond_to?('id')
"votes.user_id = #{user.id}"
@ -66,6 +71,9 @@ class Vote < ActiveRecord::Base
protected
##
# Make sure you can't vote on a photo more than once.
#
def unique_for_user
if self.user.to_s.empty? and self.session_id.empty?
self.errors.add(:vote, 'must have an owner')
@ -75,4 +83,23 @@ class Vote < ActiveRecord::Base
self.errors.add(:anonymous, 'vote has already been collected')
end
end
##
# Recalc the stats in the Photo for specific stats don't have to query the
# database.
#
def update_photo_stats
v = if self.frozen?
-1
else
1
end
self.photo.votes_count += v
if self.zero?
self.photo.zero_votes += v
else
self.photo.one_votes += v
end
self.photo.save
end
end

View File

@ -1,2 +1,52 @@
%h1 Hall of famers!
- dim = 100
%style{ :type => 'text/css' }
:sass
.top_rated_container
:width 600px
:margin-left auto
:margin-right auto
.top_rated
:width 150px
:height 130px
:margin 10px
:padding 5px
:border 1px solid #c17d11
:background-color #e9b96e
:float left
img
:display block
:margin 5px auto 5px auto
:margin-left auto
:margin-right auto
h3
:text-align center
.top_rated_number
:float left
:font-size 12px
:font-weight bold
:padding 3px
:background-color #ffffff
%h2 Top oneness
- @top_oneness.each_with_index do |p, index|
%div.top_rated_container
%div.top_rated
%span.top_rated_number= index + 1
%a{ :href => url(:photo, p) }
%img{ :src => photo_url(p, dim, dim) }
%h3== #{p.oneness}%
%br{ :style => 'clear: both' }
%h2 Top voted
- @top_voted.each_with_index do |p, index|
%div.top_rated_container
%div.top_rated
%span.top_rated_number= index + 1
%a{ :href => url(:photo, p) }
%img{ :src => photo_url(p, dim, dim) }
%h3= p.votes_count
%br{ :style => 'clear: both' }

View File

@ -32,7 +32,7 @@
%p
%strong Oneness
%br
%tt= @photo.oneness
%tt== #{@photo.oneness}%
%br{ :style => 'clear: both' }

View File

@ -6,20 +6,20 @@
- if @votes[0]
%a{ :href => url(:photo, @votes[0].photo), :onclick => 'window.open(this.href);return false;' }
%img{ :src => photo_url(@votes[0].photo, dim, dim) }
%p== <tt>#{@votes[0].to_i} / #{@votes[0].photo.oneness}</tt>
%p== <tt>#{@votes[0].to_i} / #{@votes[0].photo.oneness}%</tt>
%td{ :style => "width: 140px; height: 150px;" }
- if @votes[1]
%a{ :href => url(:photo, @votes[1].photo), :onclick => 'window.open(this.href);return false;' }
%img{ :src => photo_url(@votes[1].photo, dim, dim) }
%p== <tt>#{@votes[1].to_i} / #{@votes[1].photo.oneness}</tt>
%p== <tt>#{@votes[1].to_i} / #{@votes[1].photo.oneness}%</tt>
%tr
%td{ :style => "width: 140px; height: 150px;" }
- if @votes[2]
%a{ :href => url(:photo, @votes[2].photo), :onclick => 'window.open(this.href);return false;' }
%img{ :src => photo_url(@votes[2].photo, dim, dim) }
%p== <tt>#{@votes[2].to_i} / #{@votes[2].photo.oneness}</tt>
%p== <tt>#{@votes[2].to_i} / #{@votes[2].photo.oneness}%</tt>
%td{ :style => "width: 140px; height: 150px;" }
- if @votes[3]
%a{ :href => url(:photo, @votes[3].photo), :onclick => 'window.open(this.href);return false;' }
%img{ :src => photo_url(@votes[3].photo, dim, dim) }
%p== <tt>#{@votes[3].to_i} / #{@votes[3].photo.oneness}</tt>
%p== <tt>#{@votes[3].to_i} / #{@votes[3].photo.oneness}%</tt>

View File

@ -0,0 +1,15 @@
class CachedVoteFieldsMigration < ActiveRecord::Migration
def self.up
add_column :photos, :votes_count, :integer, :default => 0
add_column :photos, :one_votes, :integer, :default => 0
add_column :photos, :zero_votes, :integer, :default => 0
add_column :photos, :oneness, :float, :precision => 1
end
def self.down
remove_column :photos, :votes_count
remove_column :photos, :one_votes
remove_column :photos, :zero_votes
remove_column :photos, :oneness
end
end

View File

@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 5) do
ActiveRecord::Schema.define(:version => 6) do
create_table "photo_favorites", :force => true do |t|
t.integer "photo_id"
@ -27,6 +27,10 @@ ActiveRecord::Schema.define(:version => 5) do
t.integer "height"
t.datetime "created_at"
t.boolean "approved"
t.integer "votes_count", :default => 0
t.integer "one_votes", :default => 0
t.integer "zero_votes", :default => 0
t.float "oneness"
end
add_index "photos", ["email_hash"], :name => "index_photos_on_email_hash"