Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added counter cache functionality for ham comments

  • Loading branch information...
commit 2cf6cfe321da480add83a7f47e3272e4f6dcbff6 1 parent 874c63b
rsl authored
View
7 README.rdoc
@@ -6,6 +6,13 @@ ActsAsSnook is a simple and elegant method of handling comment spam that doesn't
ActsAsSnook assumes that you have the following fields on your comment model: <tt>author</tt> [string], <tt>email</tt> [string], <tt>url</tt> [string], <tt>body</tt> [text], and <tt>spam_status</tt> [string]. The name of these attributes can be changed as shown in the next section.
+ActsAsSnook can also be configured to maintain a counter cache of ham comments [ham being the opposite of spam] for you. You will need to specify the following options to enable this.
+
+* <tt>:comment_belongs_to</tt> - The name of the parent class that comments belong to.
+* <tt>:ham_comments_count_field</tt> - The name of the attribute on the parent class which maintains the counter cache.
+
+<strong>Note:</strong> Do not rely on an association setup like <tt>belongs_to :entry, :counter_cache => true</tt> for displaying comment count. The number returned there is the number of total comments, irrespective of spam status.
+
== Usage
acts_as_snook
View
78 lib/lucky_sneaks/acts_as_snook.rb
@@ -5,14 +5,23 @@ def self.included(base) # :nodoc:
end
module ClassMethods
- # Sets up spam detection (via before_validation callback). Avaiable options are:
+ # Sets up spam detection (via <tt>before_validation</tt> callback). Available options are:
#
- # +:author_field+:: Symbol or string specifying a new database field to use for the author attribute
- # +:email_field+:: Symbol or string specifying a new database field to use for the email attribute
- # +:url_field+:: Symbol or string specifying a new database field to use for the url attribute
- # +:body_field+:: Symbol or string specifying a new database field to use for the body attribute
- # +:author_field+:: Symbol or string specifying a new database field to use for the spam_status attribute
- # +:spam_words+:: Array of strings which will be added to the list of words which are considered spam markers
+ # * <tt>:author_field</tt> - Symbol or string specifying an alternate database field to use for the author attribute. Default: <tt>author</tt>
+ # * <tt>:email_field</tt> - Symbol or string specifying an alternate database field to use for the email attribute. Default: +email+
+ # * <tt>:url_field</tt> - Symbol or string specifying an alternate database field to use for the url attribute. Default: +url+
+ # * <tt>:body_field</tt> - Symbol or string specifying an alternate database field to use for the body attribute. Default: +body+
+ # * <tt>:spam_status_field</tt> - Symbol or string specifying an alternate database field to use for the spam_status attribute. Default: +spam_status+
+ # * <tt>:spam_words</tt> - Array of strings which will be added to the list of words which are considered spam markers
+ #
+ # If the comment model has only a single <tt>belongs_to</tt> association, ActsAsSnook will maintain
+ # a counter cache of ham [non-spam] comments on the parent class as the <tt>ham_comments_count</tt>
+ # attribute. If the comment model has more than one <tt>belongs_to</tt> association, ActsAsSnook will
+ # not automatically create this functionality. You can add it manually by providing the following options
+ # on the <tt>acts_as_snook</tt> call:
+ #
+ # * <tt>:comment_belongs_to</tt> - Symbol or string specifying the association that the comment has a <tt>:belongs_to</tt> relationship with.
+ # * <tt>:ham_comments_count_field</tt> - Symbol or string specifying an alternate database field to use for the ham_comments_count attribute. Default: +ham_comments_count+
def acts_as_snook(options = {})
cattr_accessor :spam_words
self.spam_words = %w{
@@ -32,15 +41,26 @@ def acts_as_snook(options = {})
cattr_accessor :fields_for_snooking
self.fields_for_snooking = {
# Defaults
- :author_field => :author,
- :email_field => :email,
- :url_field => :url,
- :body_field => :body,
- :spam_status_field => :spam_status
+ :author_field => :author,
+ :email_field => :email,
+ :url_field => :url,
+ :body_field => :body,
+ :ham_comments_count_field => :ham_comments_count,
+ :spam_status_field => :spam_status
}.merge(options)
before_validation_on_create :calculate_snook_score
+ if fields_for_snooking[:comment_belongs_to].nil? && reflect_on_all_associations(:belongs_to).size == 1
+ fields_for_snooking[:comment_belongs_to] = reflect_on_all_associations(:belongs_to).first.name
+ end
+
+ if fields_for_snooking[:comment_belongs_to]
+ after_create :increment_ham_comments_count
+ after_update :adjust_ham_comments_count
+ after_destroy :decrement_ham_comments_count
+ end
+
attr_reader :snook_credits
attr_protected fields_for_snooking[:spam_status_field]
end
@@ -50,7 +70,7 @@ def ham(options = {})
find :all, options.merge(:conditions => {fields_for_snooking[:spam_status_field] => "ham"})
end
- # Returns all instances which have been marked as being spam
+ # Returns all instances which have been marked as spam
def spam(options = {})
find :all, options.merge(:conditions => {fields_for_snooking[:spam_status_field] => "spam"})
end
@@ -85,6 +105,10 @@ def ham!
update_attribute :spam_status, "ham"
end
+ def spam!
+ update_attribute :spam_status, "spam"
+ end
+
private
def already_calculated_snook
self.send(self.class.fields_for_snooking[:spam_status_field]) || snook_credits
@@ -232,5 +256,33 @@ def previous_comments_with_same_snook_body
self.class.count :all, :conditions => conditions
end
+
+ def snook_entry
+ if self.class.fields_for_snooking[:comment_belongs_to]
+ @snook_entry ||= self.send(self.class.fields_for_snooking[:comment_belongs_to])
+ end
+ end
+
+ def snook_spam_status_changed?
+ changes.has_key? self.class.fields_for_snooking[:spam_status_field].to_s
+ end
+
+ def increment_ham_comments_count
+ if ham? && snook_entry
+ snook_entry.increment!(self.class.fields_for_snooking[:ham_comments_count_field])
+ end
+ end
+
+ def adjust_ham_comments_count
+ if snook_spam_status_changed?
+ ham? ? increment_ham_comments_count : decrement_ham_comments_count
+ end
+ end
+
+ def decrement_ham_comments_count
+ if ((frozen? && ham?) || (snook_spam_status_changed? && spam?)) && snook_entry
+ snook_entry.decrement!(self.class.fields_for_snooking[:ham_comments_count_field])
+ end
+ end
end
end
View
62 test/acts_as_snook_interface_test.rb
@@ -92,4 +92,66 @@ def test_resaving_comment_with_changed_status_does_not_mark_as_spam
@comment.save
@comment.destroy
end
+
+ def test_saving_ham_comment_increments_ham_comment_count
+ assert_difference "Entry.find(:first).ham_comments_count", 1 do
+ @comment = Entry.find(:first).comments.create!(HAM_COMMENTS[0])
+ end
+ @comment.destroy
+ end
+
+ def test_saving_spam_comment_does_not_increment_ham_comment_count
+ assert_no_difference "Entry.find(:first).ham_comments_count" do
+ @comment = Entry.find(:first).comments.create!(SPAM_COMMENTS[2])
+ end
+ @comment.destroy
+ end
+
+ def test_ham_bang_increments_ham_comment_count
+ @comment = Entry.find(:first).comments.create!(SPAM_COMMENTS[2])
+ assert_difference "Entry.find(:first).ham_comments_count", 1 do
+ @comment.ham!
+ end
+ @comment.destroy
+ end
+
+ def test_spam_bang_decrements_ham_comment_count
+ @comment = Entry.find(:first).comments.create!(HAM_COMMENTS[0])
+ assert_difference "Entry.find(:first).ham_comments_count", -1 do
+ @comment.spam!
+ end
+ @comment.destroy
+ end
+
+ def test_updating_spam_status_to_ham_increments_ham_comment_count
+ @comment = Entry.find(:first).comments.create!(SPAM_COMMENTS[2])
+ assert_difference "Entry.find(:first).ham_comments_count", 1 do
+ @comment.spam_status = "ham"
+ @comment.save!
+ end
+ @comment.destroy
+ end
+
+ def test_updating_spam_status_to_spam_decrements_ham_comment_count
+ @comment = Entry.find(:first).comments.create!(HAM_COMMENTS[0])
+ assert_difference "Entry.find(:first).ham_comments_count", -1 do
+ @comment.spam_status = "spam"
+ @comment.save!
+ end
+ @comment.destroy
+ end
+
+ def test_destroying_ham_comment_decrements_ham_comment_count
+ @comment = Entry.find(:first).comments.create!(HAM_COMMENTS[0])
+ assert_difference "Entry.find(:first).ham_comments_count", -1 do
+ @comment.destroy
+ end
+ end
+
+ def test_destroying_spam_comment_does_not_decrement_ham_comment_count
+ @comment = Entry.find(:first).comments.create!(SPAM_COMMENTS[2])
+ assert_no_difference "Entry.find(:first).ham_comments_count" do
+ @comment.destroy
+ end
+ end
end
View
3  test/test_helper.rb
@@ -19,6 +19,9 @@
require File.join(File.dirname(__FILE__), '../init')
require File.join(File.dirname(__FILE__), 'schema')
require File.join(File.dirname(__FILE__), 'comment')
+require File.join(File.dirname(__FILE__), 'entry')
+
+Entry.create!(:title => "The Tale of Flight 815")
# To shut up whining about writing to the nil logger
class NilClass
Please sign in to comment.
Something went wrong with that request. Please try again.