fuck_comments 2.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +30 -0
- data/.ruby-gemset.example +1 -0
- data/.ruby-version.example +1 -0
- data/.rvmrc.example +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +338 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/the_comments.js.coffee +108 -0
- data/app/assets/javascripts/the_comments_manage.js.coffee +27 -0
- data/app/assets/stylesheets/the_comments.css.scss +248 -0
- data/app/controllers/_templates_/comments_controller.rb +44 -0
- data/app/controllers/concerns/the_comments/controller.rb +197 -0
- data/app/controllers/concerns/the_comments/view_token.rb +20 -0
- data/app/helpers/render_comments_tree_helper.rb +111 -0
- data/app/models/_templates_/comment.rb +38 -0
- data/app/models/concerns/the_comments/comment.rb +116 -0
- data/app/models/concerns/the_comments/comment_states.rb +80 -0
- data/app/models/concerns/the_comments/commentable.rb +69 -0
- data/app/models/concerns/the_comments/user.rb +56 -0
- data/app/views/the_comments/_tree.html.erb +3 -0
- data/app/views/the_comments/haml/_additional_info.html.haml +13 -0
- data/app/views/the_comments/haml/_comment.html.haml +1 -0
- data/app/views/the_comments/haml/_comment_body.html.haml +25 -0
- data/app/views/the_comments/haml/_comment_edit.html.haml +26 -0
- data/app/views/the_comments/haml/_form.html.haml +8 -0
- data/app/views/the_comments/haml/_guest_form.html.haml +22 -0
- data/app/views/the_comments/haml/_logined_form.html.haml +18 -0
- data/app/views/the_comments/haml/_manage_controls.html.haml +30 -0
- data/app/views/the_comments/haml/_sidebar.html.haml +9 -0
- data/app/views/the_comments/haml/_sidebar_admin.html.haml +12 -0
- data/app/views/the_comments/haml/_sidebar_backlink.html.haml +3 -0
- data/app/views/the_comments/haml/_sidebar_user.html.haml +29 -0
- data/app/views/the_comments/haml/_tree.html.haml +16 -0
- data/app/views/the_comments/haml/manage.html.haml +26 -0
- data/app/views/the_comments/slim/_additional_info.html.slim +13 -0
- data/app/views/the_comments/slim/_comment.html.slim +1 -0
- data/app/views/the_comments/slim/_comment_body.html.slim +24 -0
- data/app/views/the_comments/slim/_comment_edit.html.slim +26 -0
- data/app/views/the_comments/slim/_form.html.slim +8 -0
- data/app/views/the_comments/slim/_guest_form.html.slim +22 -0
- data/app/views/the_comments/slim/_logined_form.html.slim +18 -0
- data/app/views/the_comments/slim/_manage_controls.html.slim +30 -0
- data/app/views/the_comments/slim/_sidebar.html.slim +9 -0
- data/app/views/the_comments/slim/_sidebar_admin.html.slim +12 -0
- data/app/views/the_comments/slim/_sidebar_backlink.html.slim +3 -0
- data/app/views/the_comments/slim/_sidebar_user.html.slim +29 -0
- data/app/views/the_comments/slim/_tree.html.slim +16 -0
- data/app/views/the_comments/slim/index.html.slim +18 -0
- data/app/views/the_comments/slim/manage.html.slim +26 -0
- data/app/views/the_comments/slim/my_comments.html.slim +28 -0
- data/config/initializers/the_comments.rb +15 -0
- data/config/locales/en.yml +68 -0
- data/config/locales/ru.yml +71 -0
- data/config/routes.rb +38 -0
- data/db/migrate/20130101010101_the_comments_change_user.rb +18 -0
- data/db/migrate/20130101010102_the_comments_create_comments.rb +50 -0
- data/db/migrate/20130101010103_the_comments_change_commentable.rb +13 -0
- data/docs/admin_ui_installation.md +145 -0
- data/docs/advanced_installation.md +185 -0
- data/docs/comment_api.md +58 -0
- data/docs/commentable_api.md +59 -0
- data/docs/config_file.md +27 -0
- data/docs/content_preprocessors.md +73 -0
- data/docs/customazation_of_views.md +30 -0
- data/docs/denormalization_and_recent_comments.md +40 -0
- data/docs/documentation.md +29 -0
- data/docs/generators.md +74 -0
- data/docs/pagination.md +123 -0
- data/docs/routes.md +77 -0
- data/docs/screencast.jpg +0 -0
- data/docs/the_comments.jpg +0 -0
- data/docs/the_comments_view_1.gif +0 -0
- data/docs/the_comments_view_2.gif +0 -0
- data/docs/the_comments_view_3.gif +0 -0
- data/docs/the_comments_view_4.gif +0 -0
- data/docs/the_comments_view_5.gif +0 -0
- data/docs/user_api.md +75 -0
- data/docs/what_is_comcoms.md +63 -0
- data/docs/whats_wrong_with_other_gems.md +28 -0
- data/docs/where_is_example_application.md +37 -0
- data/gem_version.rb +3 -0
- data/lib/generators/the_comments/USAGE +44 -0
- data/lib/generators/the_comments/the_comments_generator.rb +56 -0
- data/lib/generators/the_comments/views_generator.rb +79 -0
- data/lib/the_comments/config.rb +39 -0
- data/lib/the_comments/version.rb +1 -0
- data/lib/the_comments.rb +27 -0
- data/spec/dummy_app/.gitignore +18 -0
- data/spec/dummy_app/.rspec +1 -0
- data/spec/dummy_app/Gemfile +43 -0
- data/spec/dummy_app/README.md +33 -0
- data/spec/dummy_app/Rakefile +6 -0
- data/spec/dummy_app/app/assets/images/.keep +0 -0
- data/spec/dummy_app/app/assets/javascripts/admin_panel.js +5 -0
- data/spec/dummy_app/app/assets/javascripts/application.js +16 -0
- data/spec/dummy_app/app/assets/stylesheets/admin_panel.css +3 -0
- data/spec/dummy_app/app/assets/stylesheets/app.css.scss +4 -0
- data/spec/dummy_app/app/assets/stylesheets/application.css +16 -0
- data/spec/dummy_app/app/controllers/application_controller.rb +7 -0
- data/spec/dummy_app/app/controllers/comments_controller.rb +28 -0
- data/spec/dummy_app/app/controllers/concerns/.keep +0 -0
- data/spec/dummy_app/app/controllers/posts_controller.rb +13 -0
- data/spec/dummy_app/app/controllers/users_controller.rb +7 -0
- data/spec/dummy_app/app/helpers/application_helper.rb +2 -0
- data/spec/dummy_app/app/mailers/.keep +0 -0
- data/spec/dummy_app/app/models/.keep +0 -0
- data/spec/dummy_app/app/models/comment.rb +32 -0
- data/spec/dummy_app/app/models/concerns/.keep +0 -0
- data/spec/dummy_app/app/models/post.rb +17 -0
- data/spec/dummy_app/app/models/user.rb +21 -0
- data/spec/dummy_app/app/views/layouts/admin.html.haml +25 -0
- data/spec/dummy_app/app/views/layouts/application.html.haml +20 -0
- data/spec/dummy_app/app/views/posts/index.html.haml +22 -0
- data/spec/dummy_app/app/views/posts/show.html.haml +7 -0
- data/spec/dummy_app/bin/bundle +3 -0
- data/spec/dummy_app/bin/rails +4 -0
- data/spec/dummy_app/bin/rake +4 -0
- data/spec/dummy_app/config/application.rb +23 -0
- data/spec/dummy_app/config/boot.rb +4 -0
- data/spec/dummy_app/config/database.yml +11 -0
- data/spec/dummy_app/config/environment.rb +5 -0
- data/spec/dummy_app/config/environments/development.rb +29 -0
- data/spec/dummy_app/config/environments/production.rb +80 -0
- data/spec/dummy_app/config/environments/test.rb +36 -0
- data/spec/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy_app/config/initializers/inflections.rb +16 -0
- data/spec/dummy_app/config/initializers/mime_types.rb +5 -0
- data/spec/dummy_app/config/initializers/secret_token.rb +12 -0
- data/spec/dummy_app/config/initializers/session_store.rb +3 -0
- data/spec/dummy_app/config/initializers/sorcery.rb +437 -0
- data/spec/dummy_app/config/initializers/the_comments.rb +15 -0
- data/spec/dummy_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy_app/config/locales/en.yml +23 -0
- data/spec/dummy_app/config/routes.rb +19 -0
- data/spec/dummy_app/config.ru +4 -0
- data/spec/dummy_app/db/migrate/20130712061503_sorcery_core.rb +16 -0
- data/spec/dummy_app/db/migrate/20130712065951_create_posts.rb +11 -0
- data/spec/dummy_app/db/migrate/20131027185332_change_user.the_comments_engine.rb +19 -0
- data/spec/dummy_app/db/migrate/20131027185333_create_comments.the_comments_engine.rb +51 -0
- data/spec/dummy_app/db/migrate/20131027185334_change_commentable.the_comments_engine.rb +14 -0
- data/spec/dummy_app/db/schema.rb +74 -0
- data/spec/dummy_app/db/seeds.rb +42 -0
- data/spec/dummy_app/lib/assets/.keep +0 -0
- data/spec/dummy_app/lib/tasks/.keep +0 -0
- data/spec/dummy_app/lib/tasks/app_bootstrap.rake +15 -0
- data/spec/dummy_app/log/.keep +0 -0
- data/spec/dummy_app/public/404.html +58 -0
- data/spec/dummy_app/public/422.html +58 -0
- data/spec/dummy_app/public/500.html +57 -0
- data/spec/dummy_app/public/favicon.ico +0 -0
- data/spec/dummy_app/public/robots.txt +5 -0
- data/spec/dummy_app/spec/factories/post.rb +6 -0
- data/spec/dummy_app/spec/factories/user.rb +6 -0
- data/spec/dummy_app/spec/models/user_counters_spec.rb +339 -0
- data/spec/dummy_app/spec/spec_helper.rb +29 -0
- data/spec/dummy_app/test/controllers/.keep +0 -0
- data/spec/dummy_app/test/fixtures/.keep +0 -0
- data/spec/dummy_app/test/helpers/.keep +0 -0
- data/spec/dummy_app/test/integration/.keep +0 -0
- data/spec/dummy_app/test/mailers/.keep +0 -0
- data/spec/dummy_app/test/models/.keep +0 -0
- data/spec/dummy_app/test/test_helper.rb +15 -0
- data/spec/dummy_app/vendor/assets/javascripts/.keep +0 -0
- data/spec/dummy_app/vendor/assets/stylesheets/.keep +0 -0
- data/the_comments.gemspec +23 -0
- data/views_converter.rb +16 -0
- metadata +332 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module TheComments
|
2
|
+
# Cookies and View token for spam protection
|
3
|
+
# include TheComments::ViewToken
|
4
|
+
module ViewToken
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included { before_action :set_the_comments_cookies }
|
8
|
+
|
9
|
+
def comments_view_token
|
10
|
+
cookies[:comments_view_token]
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def set_the_comments_cookies
|
16
|
+
cookies[:the_comment_cookies] = { value: TheComments::COMMENTS_COOKIES_TOKEN, expires: 1.year.from_now, domain: TheComments.config.cookie_domain }
|
17
|
+
cookies[:comments_view_token] = { value: SecureRandom.hex, expires: 7.days.from_now, domain: TheComments.config.cookie_domain } unless cookies[:comments_view_token]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
# DOC:
|
3
|
+
# We use Helper Methods for tree building,
|
4
|
+
# because it's faster than View Templates and Partials
|
5
|
+
|
6
|
+
# SECURITY note
|
7
|
+
# Prepare your data on server side for rendering
|
8
|
+
# or use h.html_escape(node.content)
|
9
|
+
# for escape potentially dangerous content
|
10
|
+
module RenderCommentsTreeHelper
|
11
|
+
module Render
|
12
|
+
class << self
|
13
|
+
attr_accessor :h, :options
|
14
|
+
|
15
|
+
# Main Helpers
|
16
|
+
def controller
|
17
|
+
@options[:controller]
|
18
|
+
end
|
19
|
+
|
20
|
+
def t str
|
21
|
+
controller.t str
|
22
|
+
end
|
23
|
+
|
24
|
+
# Render Helpers
|
25
|
+
def visible_draft?
|
26
|
+
controller.try(:comments_view_token) == @comment.view_token
|
27
|
+
end
|
28
|
+
|
29
|
+
def moderator?
|
30
|
+
controller.try(:current_user).try(:comments_moderator?, @comment)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Render Methods
|
34
|
+
def render_node(h, options)
|
35
|
+
@h, @options = h, options
|
36
|
+
@comment = options[:node]
|
37
|
+
|
38
|
+
@max_reply_depth = options[:max_reply_depth] || TheComments.config.max_reply_depth
|
39
|
+
|
40
|
+
if @comment.draft?
|
41
|
+
draft_comment
|
42
|
+
else @comment.published?
|
43
|
+
published_comment
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def draft_comment
|
48
|
+
if visible_draft? || moderator?
|
49
|
+
published_comment
|
50
|
+
else
|
51
|
+
"<li class='draft'>
|
52
|
+
<div class='comment draft' id='comment_#{@comment.anchor}'>
|
53
|
+
#{ t('the_comments.waiting_for_moderation') }
|
54
|
+
#{ h.link_to '#', '#comment_' + @comment.anchor }
|
55
|
+
</div>
|
56
|
+
#{ children }
|
57
|
+
</li>"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def published_comment
|
62
|
+
"<li>
|
63
|
+
<div id='comment_#{@comment.anchor}' class='comment #{@comment.state}' data-comment-id='#{@comment.to_param}'>
|
64
|
+
<div>
|
65
|
+
#{ avatar }
|
66
|
+
#{ userbar }
|
67
|
+
<div class='cbody'>#{ @comment.content }</div>
|
68
|
+
#{ reply }
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
|
72
|
+
<div class='form_holder'></div>
|
73
|
+
#{ children }
|
74
|
+
</li>"
|
75
|
+
end
|
76
|
+
|
77
|
+
def avatar
|
78
|
+
"<div class='userpic'>
|
79
|
+
<img src='#{ @comment.avatar_url }' alt='userpic' />
|
80
|
+
#{ controls }
|
81
|
+
</div>"
|
82
|
+
end
|
83
|
+
|
84
|
+
def userbar
|
85
|
+
anchor = h.link_to('#', '#comment_' + @comment.anchor)
|
86
|
+
title = @comment.title.blank? ? t('the_comments.guest_name') : @comment.title
|
87
|
+
"<div class='userbar'>#{ title } #{ anchor }</div>"
|
88
|
+
end
|
89
|
+
|
90
|
+
def moderator_controls
|
91
|
+
if moderator?
|
92
|
+
h.link_to(t('the_comments.edit'), h.edit_comment_url(@comment), class: :edit)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def reply
|
97
|
+
if @comment.depth < (@max_reply_depth - 1)
|
98
|
+
"<p class='reply'><a href='#' class='reply_link'>#{ t('the_comments.reply') }</a>"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def controls
|
103
|
+
"<div class='controls'>#{ moderator_controls }</div>"
|
104
|
+
end
|
105
|
+
|
106
|
+
def children
|
107
|
+
"<ol class='nested_set'>#{ options[:children] }</ol>"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Comment < ActiveRecord::Base
|
2
|
+
include TheComments::Comment
|
3
|
+
# ---------------------------------------------------
|
4
|
+
# Define comment's avatar url
|
5
|
+
# Usually we use Comment#user (owner of comment) to define avatar
|
6
|
+
# @blog.comments.includes(:user) <= use includes(:user) to decrease queries count
|
7
|
+
# comment#user.avatar_url
|
8
|
+
# ---------------------------------------------------
|
9
|
+
|
10
|
+
# public
|
11
|
+
# ---------------------------------------------------
|
12
|
+
# Simple way to define avatar url
|
13
|
+
#
|
14
|
+
# def avatar_url
|
15
|
+
# src = id.to_s
|
16
|
+
# src = title unless title.blank?
|
17
|
+
# src = contacts if !contacts.blank? && /@/ =~ contacts
|
18
|
+
# hash = Digest::MD5.hexdigest(src)
|
19
|
+
# "https://2.gravatar.com/avatar/#{hash}?s=42&d=https://identicons.github.com/#{hash}.png"
|
20
|
+
# end
|
21
|
+
# ---------------------------------------------------
|
22
|
+
|
23
|
+
# private
|
24
|
+
# ---------------------------------------------------
|
25
|
+
# Define your content filters
|
26
|
+
# gem 'RedCloth'
|
27
|
+
# gem 'sanitize'
|
28
|
+
# gem 'MySmilesProcessor'
|
29
|
+
#
|
30
|
+
# def prepare_content
|
31
|
+
# text = self.raw_content
|
32
|
+
# text = RedCloth.new(text).to_html
|
33
|
+
# text = MySmilesProcessor.new(text)
|
34
|
+
# text = Sanitize.clean(text, Sanitize::Config::RELAXED)
|
35
|
+
# self.content = text
|
36
|
+
# end
|
37
|
+
# ---------------------------------------------------
|
38
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module TheComments
|
2
|
+
module Comment
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
scope :active, -> { with_state [:draft, :published] }
|
7
|
+
scope :with_users, -> { includes(:user) }
|
8
|
+
|
9
|
+
# Nested Set
|
10
|
+
acts_as_nested_set scope: [:commentable_type, :commentable_id]
|
11
|
+
|
12
|
+
# simple sort scopes
|
13
|
+
include ::TheSimpleSort::Base
|
14
|
+
|
15
|
+
# TheSortableTree
|
16
|
+
include ::TheSortableTree::Scopes
|
17
|
+
|
18
|
+
# Comments State Machine
|
19
|
+
include TheComments::CommentStates
|
20
|
+
|
21
|
+
validates :raw_content, presence: true
|
22
|
+
|
23
|
+
# relations
|
24
|
+
belongs_to :user
|
25
|
+
belongs_to :holder, class_name: :User
|
26
|
+
belongs_to :commentable, polymorphic: true
|
27
|
+
|
28
|
+
# callbacks
|
29
|
+
before_create :define_holder, :define_default_state, :define_anchor, :denormalize_commentable
|
30
|
+
after_create :update_cache_counters
|
31
|
+
before_save :prepare_content
|
32
|
+
end
|
33
|
+
|
34
|
+
def header_title
|
35
|
+
title.present? ? title : I18n.t('the_comments.guest_name')
|
36
|
+
end
|
37
|
+
|
38
|
+
def user_name
|
39
|
+
user.try(:username) || user.try(:login) || header_title
|
40
|
+
end
|
41
|
+
|
42
|
+
def avatar_url
|
43
|
+
src = id.to_s
|
44
|
+
src = title unless title.blank?
|
45
|
+
src = contacts if !contacts.blank? && /@/ =~ contacts
|
46
|
+
hash = Digest::MD5.hexdigest(src)
|
47
|
+
"https://2.gravatar.com/avatar/#{hash}?s=42&d=https://identicons.github.com/#{hash}.png"
|
48
|
+
end
|
49
|
+
|
50
|
+
def mark_as_spam
|
51
|
+
count = self_and_descendants.update_all({spam: true})
|
52
|
+
update_spam_counter
|
53
|
+
count
|
54
|
+
end
|
55
|
+
|
56
|
+
def mark_as_not_spam
|
57
|
+
count = self_and_descendants.update_all({spam: false})
|
58
|
+
update_spam_counter
|
59
|
+
count
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_spam
|
63
|
+
mark_as_spam
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def update_spam_counter
|
69
|
+
holder.try :update_comcoms_spam_counter
|
70
|
+
end
|
71
|
+
|
72
|
+
def define_anchor
|
73
|
+
self.anchor = SecureRandom.hex[0..5]
|
74
|
+
end
|
75
|
+
|
76
|
+
def define_holder
|
77
|
+
c = self.commentable
|
78
|
+
self.holder = c.is_a?(User) ? c : c.try(:user)
|
79
|
+
end
|
80
|
+
|
81
|
+
def define_default_state
|
82
|
+
self.state = TheComments.config.default_owner_state if user && user == holder
|
83
|
+
end
|
84
|
+
|
85
|
+
def denormalize_commentable
|
86
|
+
self.commentable_title = commentable.try :commentable_title
|
87
|
+
self.commentable_state = commentable.try :commentable_state
|
88
|
+
self.commentable_url = commentable.try :commentable_url
|
89
|
+
end
|
90
|
+
|
91
|
+
def prepare_content
|
92
|
+
self.content = self.raw_content
|
93
|
+
end
|
94
|
+
|
95
|
+
# Warn: increment! doesn't call validation =>
|
96
|
+
# before_validation filters doesn't work =>
|
97
|
+
# We have few unuseful requests
|
98
|
+
# I impressed that I found it and reduce DB requests
|
99
|
+
# Awesome logic pazzl! I'm really pedant :D
|
100
|
+
def update_cache_counters
|
101
|
+
user.try :recalculate_my_comments_counter!
|
102
|
+
|
103
|
+
if holder
|
104
|
+
holder.send :try, :define_denormalize_flags
|
105
|
+
holder.increment! "#{ state }_comcoms_count"
|
106
|
+
# holder.class.increment_counter("#{ state }_comcoms_count", holder.id)
|
107
|
+
end
|
108
|
+
|
109
|
+
if commentable
|
110
|
+
commentable.send :define_denormalize_flags
|
111
|
+
commentable.increment! "#{ state }_comments_count"
|
112
|
+
# holder.class.increment_counter("#{ state }_comments_count", holder.id)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module TheComments
|
2
|
+
module CommentStates
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
# :draft | :published | :deleted
|
7
|
+
state_machine :state, :initial => TheComments.config.default_state do
|
8
|
+
|
9
|
+
# events
|
10
|
+
event :to_draft do
|
11
|
+
transition all - :draft => :draft
|
12
|
+
end
|
13
|
+
|
14
|
+
event :to_published do
|
15
|
+
transition all - :published => :published
|
16
|
+
end
|
17
|
+
|
18
|
+
event :to_deleted do
|
19
|
+
transition any - :deleted => :deleted
|
20
|
+
end
|
21
|
+
|
22
|
+
# transition callbacks
|
23
|
+
after_transition any => any do |comment|
|
24
|
+
@comment = comment
|
25
|
+
@owner = comment.user
|
26
|
+
@holder = comment.holder
|
27
|
+
@commentable = comment.commentable
|
28
|
+
end
|
29
|
+
|
30
|
+
# between draft and published
|
31
|
+
after_transition [:draft, :published] => [:draft, :published] do |comment, transition|
|
32
|
+
from = transition.from_name
|
33
|
+
to = transition.to_name
|
34
|
+
|
35
|
+
if @holder
|
36
|
+
@holder.send :try, :define_denormalize_flags
|
37
|
+
@holder.increment! "#{to}_comcoms_count"
|
38
|
+
@holder.decrement! "#{from}_comcoms_count"
|
39
|
+
end
|
40
|
+
|
41
|
+
if @commentable
|
42
|
+
@commentable.send :define_denormalize_flags
|
43
|
+
@commentable.increment! "#{to}_comments_count"
|
44
|
+
@commentable.decrement! "#{from}_comments_count"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# to deleted (cascade like query)
|
49
|
+
after_transition [:draft, :published] => :deleted do |comment|
|
50
|
+
ids = comment.self_and_descendants.map(&:id)
|
51
|
+
::Comment.where(id: ids).update_all(state: :deleted)
|
52
|
+
|
53
|
+
@owner.try :recalculate_my_comments_counter!
|
54
|
+
@holder.try :recalculate_comcoms_counters!
|
55
|
+
@commentable.try :recalculate_comments_counters!
|
56
|
+
end
|
57
|
+
|
58
|
+
# from deleted
|
59
|
+
after_transition :deleted => [:draft, :published] do |comment, transition|
|
60
|
+
to = transition.to_name
|
61
|
+
comment.mark_as_not_spam
|
62
|
+
|
63
|
+
@owner.try :recalculate_my_comments_counter!
|
64
|
+
|
65
|
+
if @holder
|
66
|
+
@holder.send :try, :define_denormalize_flags
|
67
|
+
@holder.decrement! :deleted_comcoms_count
|
68
|
+
@holder.increment! "#{to}_comcoms_count"
|
69
|
+
end
|
70
|
+
|
71
|
+
if @commentable
|
72
|
+
@commentable.send :define_denormalize_flags
|
73
|
+
@commentable.decrement! :deleted_comments_count
|
74
|
+
@commentable.increment! "#{to}_comments_count"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module TheComments
|
2
|
+
module Commentable
|
3
|
+
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :comments, as: :commentable
|
8
|
+
|
9
|
+
# *define_denormalize_flags* - should be placed before title or url builder filters
|
10
|
+
before_validation :define_denormalize_flags
|
11
|
+
after_save :denormalize_for_comments, if: -> { !id_changed? }
|
12
|
+
end
|
13
|
+
|
14
|
+
# Default Denormalization methods
|
15
|
+
# Overwrite it with your Application
|
16
|
+
def commentable_title
|
17
|
+
# My first blog post
|
18
|
+
try(:title) || TheComments.config.default_title
|
19
|
+
end
|
20
|
+
|
21
|
+
def commentable_url
|
22
|
+
# /posts/1
|
23
|
+
['', self.class.to_s.tableize, self.to_param].join('/')
|
24
|
+
end
|
25
|
+
|
26
|
+
def commentable_state
|
27
|
+
# 'draft'
|
28
|
+
try(:state)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Helper methods
|
32
|
+
def comments_sum
|
33
|
+
published_comments_count + draft_comments_count
|
34
|
+
end
|
35
|
+
|
36
|
+
def recalculate_comments_counters!
|
37
|
+
update_attributes!({
|
38
|
+
draft_comments_count: comments.with_state(:draft).count,
|
39
|
+
published_comments_count: comments.with_state(:published).count,
|
40
|
+
deleted_comments_count: comments.with_state(:deleted).count
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def define_denormalize_flags
|
47
|
+
@trackable_commentable_title = commentable_title
|
48
|
+
@trackable_commentable_state = commentable_state
|
49
|
+
@trackable_commentable_url = commentable_url
|
50
|
+
end
|
51
|
+
|
52
|
+
def denormalization_fields_changed?
|
53
|
+
a = @trackable_commentable_title != commentable_title
|
54
|
+
b = @trackable_commentable_state != commentable_state
|
55
|
+
c = @trackable_commentable_url != commentable_url
|
56
|
+
a || b || c
|
57
|
+
end
|
58
|
+
|
59
|
+
def denormalize_for_comments
|
60
|
+
if denormalization_fields_changed?
|
61
|
+
comments.update_all({
|
62
|
+
commentable_title: commentable_title,
|
63
|
+
commentable_state: commentable_state,
|
64
|
+
commentable_url: commentable_url
|
65
|
+
})
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module TheComments
|
2
|
+
module User
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :comcoms, class_name: :Comment, foreign_key: :holder_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def my_comments; ::Comment.where(user: self); end
|
10
|
+
|
11
|
+
%w[draft published deleted].each do |state|
|
12
|
+
define_method "my_#{state}_comments" do
|
13
|
+
my_comments.with_state state
|
14
|
+
end
|
15
|
+
|
16
|
+
define_method "#{state}_comcoms" do
|
17
|
+
comcoms.with_state state
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def my_spam_comments
|
22
|
+
my_comments.where(spam: true)
|
23
|
+
end
|
24
|
+
|
25
|
+
# I think we shouldn't to have my_deleted_comments cache counter
|
26
|
+
def recalculate_my_comments_counter!
|
27
|
+
dcount = my_draft_comments.count
|
28
|
+
pcount = my_published_comments.count
|
29
|
+
update_attributes!({
|
30
|
+
my_draft_comments_count: dcount,
|
31
|
+
my_published_comments_count: pcount,
|
32
|
+
my_comments_count: dcount + pcount
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
def recalculate_comcoms_counters!
|
37
|
+
update_attributes!({
|
38
|
+
draft_comcoms_count: draft_comcoms.count,
|
39
|
+
published_comcoms_count: published_comcoms.count,
|
40
|
+
deleted_comcoms_count: deleted_comcoms.count
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_comcoms_spam_counter
|
45
|
+
update!(spam_comcoms_count: comcoms.where(spam: true).count)
|
46
|
+
end
|
47
|
+
|
48
|
+
def comments_sum
|
49
|
+
published_comments_count + draft_comments_count
|
50
|
+
end
|
51
|
+
|
52
|
+
def comcoms_sum
|
53
|
+
published_comcoms_count + draft_comcoms_count
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|