adding cached vote stats fields and hall of famers
parent
e8e0cb98d0
commit
675e244864
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' }
|
|
@ -32,7 +32,7 @@
|
|||
%p
|
||||
%strong Oneness
|
||||
%br
|
||||
%tt= @photo.oneness
|
||||
%tt== #{@photo.oneness}%
|
||||
|
||||
%br{ :style => 'clear: both' }
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
|
Reference in New Issue