Skip to content

Instantly share code, notes, and snippets.

@maxlapshin
Created July 30, 2009 18:01
Show Gist options
  • Save maxlapshin/158813 to your computer and use it in GitHub Desktop.
Save maxlapshin/158813 to your computer and use it in GitHub Desktop.
# = Schema Information
#
# Table name: *comments*
#
# id :integer not null, primary key
# user_id :integer not null
# commentable_id :integer not null
# commentable_type :string(255) not null
# body :text
# parent_id :integer
# created_at :datetime
# updated_at :datetime
# page :integer not null
# body_html :text
########
class Comment < ActiveRecord::Base
## included modules & attr_*
attr_accessor :children
attr_accessor :subscribe
## associations
belongs_to :commentable, :polymorphic => true, :counter_cache => true
has_many :child_comments, :class_name => "Comment", :foreign_key => "parent_id"
belongs_to :parent, :class_name => "Comment"
belongs_to :user, :counter_cache => true
## plugins
htmlize :body
## named_scopes
named_scope :recent, :order => "created_at DESC"
named_scope :prophotos, :conditions => {:commentable_type => %w(Article Device Vendor Video)}
named_scope :related, lambda {|device_kind, vendor_id|
{ :select => "DISTINCT comments.*",
:conditions => "devices.id IS NOT NULL OR articles.id IS NOT NULL",
:joins => <<-SQL
LEFT OUTER JOIN devices ON
(comments.commentable_type ='Device' AND devices.id = comments.commentable_id AND devices.kind = #{connection.quote(device_kind)})
LEFT OUTER JOIN articles ON
(comments.commentable_type ='Article' AND articles.id = comments.commentable_id AND articles.type = 'News' AND articles.vendor_id = #{connection.quote(vendor_id)})
SQL
}
}
named_scope :commentables, :select => "commentable_type, commentable_id", :group => "commentable_type, commentable_id"
## validations
validates_presence_of :commentable_type, :message => "can't be blank"
validates_presence_of :commentable_id, :message => "can't be blank"
validates_presence_of :user_id, :message => "can't be blank"
validates_presence_of :body, :message => "can't be blank"
validates_length_of :body, :within => 1..2000000, :message => "must be present"
## callbacks
before_create :calculate_page
after_create :after_calculate_pages
before_create :auto_subscribe
## class methods
def self.per_page; 30; end
def self.tree(options = {})
page = options.delete(:page).to_i
page = 1 if page < 1
comment_list = all(:include => :user, :order => "created_at", :conditions => {:page => page})
total_count = maximum("page").to_i*per_page
map = comment_list.inject({}) {|list, comment| (list[comment.parent_id.to_i] ||= []) << comment; list }
comment_list.each {|comment| comment.children = map[comment.id]}
tree = map[0] || []
collection = WillPaginate::Collection.new(page, per_page, total_count)
collection.replace(tree)
collection
end
def self.update_pages
comment_list = all(:select => "id, parent_id, created_at", :order => "created_at DESC")
map = comment_list.inject({}) {|list, comment| (list[comment.parent_id.to_i] ||= []) << comment; list }
comment_list.each {|comment| comment.children = map[comment.id]}
pages = []
return unless map[0]
map[0].each_slice(per_page) {|slice| pages << slice}
pages.each_with_index do |group, page|
Comment.update_all({:page => page+1}, {:id => (group + group.map(&:deep_children)).flatten.map(&:id)})
end
end
def self.cached_count
Rails.cache.fetch("comments:count", :expires => 1.day) { count }
end
def self.user_count
count("DISTINCT user_id")
end
## public methods
def subscription
@subscription ||=
CommentSubscription.find_by_user_id_and_content_id_and_content_type(user_id,
commentable_id,
commentable_type)
end
def deep_children
return [] unless children
children + children.map(&:deep_children).compact
end
def was_edited?
updated_at && (created_at.nil? || updated_at > created_at)
end
## private methods
protected
def auto_subscribe
return true unless @subscribe
CommentSubscription.find_or_create_by_user_id_and_content_id_and_content_type(user_id,
commentable_id,
commentable_type)
end
def calculate_page
if parent
self.page = parent.page
else
self.page = 1
@after_calculate_pages = true
end
true
end
def after_calculate_pages
send_later(:update_pages) if @after_calculate_pages
end
def update_pages
commentable.comments.update_pages
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment