the_comments 0.9.0 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,157 +1,202 @@
1
- # TheComments 0.9.0
1
+ # TheComments 1.0.0
2
+
3
+ TheComments - just comment system for my Ruby on Rails 4 projects
4
+
5
+ P.S: and for me it's best prototype of comment system for Rails 4
6
+
7
+ ## Keywords
8
+
9
+ Comments for Rails 4, Comments with threading, Nested Comments, Polymorphic comments, Acts as commentable, Comment functionality, Comments, Threading, Rails 4, Comments with moderation, I hate captcha for comments!
10
+
11
+ ## Screenshots
12
+
13
+ **click to zoom**
14
+
15
+ <table>
16
+ <tr>
17
+ <td width="20%">Guest view</td>
18
+ <td width="20%">Admin view</td>
19
+ <td width="20%">Edit</td>
20
+ <td width="20%">Cache counters & User Cabinet</td>
21
+ <td width="20%">Recent comments & Denormalization</td>
22
+ </tr>
23
+ <tr>
24
+ <td width="20%"><img width="100%" height="100%" src="https://raw.github.com/open-cook/the_comments/master/docs/the_comments_view_2.gif" alt="the_comments"></td>
25
+ <td width="20%"><img width="100%" height="100%" src="https://raw.github.com/open-cook/the_comments/master/docs/the_comments_view_1.gif" alt="the_comments"></td>
26
+ <td width="20%"><img width="100%" height="100%" src="https://raw.github.com/open-cook/the_comments/master/docs/the_comments_view_4.gif" alt="the_comments"></td>
27
+ <td width="20%"><img width="100%" height="100%" src="https://raw.github.com/open-cook/the_comments/master/docs/the_comments_view_3.gif" alt="the_comments"></td>
28
+ <td width="20%"><img width="100%" height="100%" src="https://raw.github.com/open-cook/the_comments/master/docs/the_comments_view_5.gif" alt="the_comments"></td>
29
+ </tr>
30
+ </table>
31
+
32
+ ### Main features
33
+
34
+ * Threaded comments
35
+ * Tree rendering via [TheSortableTree](https://github.com/the-teacher/the_sortable_tree)
36
+ * [Denormalization](#denormalization) for Recent comments
37
+ * Usefull cache counters
38
+ * Basic AntiSpam system
39
+ * Online Support via skype: **ilya.killich**
40
+
41
+ ### Intro (understanding)
42
+
43
+ * [My hopes about comments system](#my-hopes-about-comments-system)
44
+ * [What's wrong with other gems?](#whats-wrong-with-other-gems)
45
+ * [Comments, Posted comments & ComComs](#comments-posted-comments-comcoms)
46
+ * [Denormalization and Recent comments](#denormalization)
47
+ * [Recent comments building](#recent-comments-building)
48
+ * [AntiSpam system](#antispam-system)
49
+ * [Customization](#customization)
50
+ * [User methods](#user-methods)
51
+ * [Commentable methods](#commentable-methods)
52
+ * [Online Support](#online-support)
53
+ * [About author](#about-author)
2
54
 
3
- TheComments - probably, best solution for comments for Ruby on Rails.
55
+ ## Installation
4
56
 
5
- ### What's wrong with other gems?
57
+ This gem has many steps to install. Be careful when installing and keep calm.
6
58
 
7
- Just look at [Ruby-Toolbox](https://www.ruby-toolbox.com/categories/rails_comments). What we can see?
59
+ Just follow an installation instruction step by step and everything will be fine!
8
60
 
9
- * [Acts as commentable with threading](https://github.com/elight/acts_as_commentable_with_threading) - so, guys, where is the render helper for the tree? There is no helper! Should I make render helper for tree by myself? Nooooo!!! I'm so sorry, but I can't use this gem.
10
- * [acts_as_commentable](https://github.com/jackdempsey/acts_as_commentable) - so, I can see code for models. But I can't see code for controllers and views. Unfortunately, there is no threading. It's not enough for me.
11
- * [opinio](https://github.com/Draiken/opinio) - looks better, but there is no threading. I want to have more!
12
- * [has_threaded_comments](https://github.com/aarongough/has_threaded_comments) - Nice work! Nice gem! Models, controllers, views, view helper for tree rendering! **But**, last activity 2 years ago, I need few features, I think - I can make it better.
61
+ **Installation process consist of 4 main steps:**
13
62
 
14
- ### In sum
63
+ * [Gem Installation](#gem-installation)
64
+ * [Code Installation](#code-installation)
65
+ * [Tuning](#tuning)
66
+ * [Using](#using)
15
67
 
16
- ![TheComments](https://raw.github.com/open-cook/the_comments/master/the_comments.jpg)
68
+ ## Gem Installation
17
69
 
18
- ### My hopes about comments system
19
-
20
- * Open comments for everybody (by default). *I hate user registration*
21
- * Moderation for comments and simple Admin UI
22
- * Spam traps instead Captcha. *I hate Captcha*
23
- * Blacklists for IP and UserAgent
24
- * Comment counters for commentable objects and User
25
- * Denormalization for fast and Request-free comment list building
26
- * Ready for external content filters ( **sanitize**, **RedCloth**, **Markdown**)
27
- * Ready for Rails4 (and Rails::Engine)
28
- * Delete without destroy
29
-
30
- ### Requires
70
+ **1)** change your Gemfile
31
71
 
32
72
  ```ruby
73
+ # I use *awesome_nested_set* gem to provide threading for comments
74
+ # But you can use other nested set gem, for example:
75
+ # gem 'nested_set' (github.com/skyeagle/nested_set)
33
76
  gem 'awesome_nested_set'
34
- gem 'the_sortable_tree'
35
- gem 'state_machine'
77
+
78
+ # I use haml for default views
79
+ # You can remove this dependancy,
80
+ # but you will should rewrite default views with your template engine
81
+ gem 'haml'
82
+
83
+ # finally, this gem
84
+ gem 'the_comments'
36
85
  ```
37
86
 
38
- ### Anti Spam system
87
+ **2)** bundle
39
88
 
40
- User agent must have:
89
+ **3)** Copy migration file into application, <b>OPEN FILE AND FOLLOW AN INSTRUCTION</b>.
41
90
 
42
- * Cookies support
43
- * JavaScript and Ajax support
91
+ ```ruby
92
+ bundle exec rake the_comments_engine:install:migrations
93
+ ```
44
94
 
45
- _Usually spambot not support Cookies and JavaScript_
95
+ **4)** run migration
46
96
 
47
- Comment form has:
97
+ ```ruby
98
+ bundle exec rake db:migrate
99
+ ```
48
100
 
49
- * fake (hidden) fields
101
+ ## Code Installation
50
102
 
51
- _Usually spam bot puts data in fake inputs_
103
+ **1)** Assets
52
104
 
53
- Trap via time:
105
+ *app/assets/javascripts/application.js*
54
106
 
55
- * User should be few seconds on page, before comment sending (by default 5 sec)
107
+ ```js
108
+ //= require the_comments
109
+ //= require the_comments_manage
110
+ ```
56
111
 
57
- _Usually spam bots works faster, than human. We can try to use this feature of behavior_
112
+ *app/assets/stylesheets/application.css*
58
113
 
59
- ## Installation
114
+ ```css
115
+ *= require the_comments
116
+ ```
117
+
118
+ **2)** Change your ApplicationController
60
119
 
61
120
  ```ruby
62
- gem 'the_comments'
121
+ class ApplicationController < ActionController::Base
122
+ include TheCommentsController::ViewToken
123
+ end
63
124
  ```
64
125
 
65
- **bundle**
126
+ **3)** Run generator, <b>OPEN EACH OF CREATED FILES AND FOLLOW INSTRUCTIONS</b>.
66
127
 
67
128
  ```ruby
68
- bundle exec rails g the_comment install
129
+ bundle exec rails g the_comments install
69
130
  ```
70
131
 
71
- ### Assets
132
+ *List of created files:*
72
133
 
73
- **app/assets/javascripts/application.js**
134
+ ```ruby
135
+ config/initializers/the_comments.rb
74
136
 
75
- ```js
76
- //= require the_comments
137
+ app/controllers/comments_controller.rb
138
+ app/controllers/ip_black_lists_controller.rb
139
+ app/controllers/user_agent_black_lists_controller.rb
77
140
  ```
78
141
 
79
- **app/assets/stylesheets/application.css**
142
+ **4)** Copy view files into your application
80
143
 
81
- ```css
82
- /*
83
- *= require the_comments
84
- */
144
+ ```ruby
145
+ bundle exec rails g the_comments:views views
85
146
  ```
86
147
 
148
+ *List of created directories with view files:*
149
+
150
+ ```ruby
151
+ app/views/the_comments/*.haml
152
+ app/views/ip_black_lists/*.haml
153
+ app/views/user_agent_black_lists/*.haml
154
+ ```
155
+
156
+ ## Tuning
157
+
87
158
  ### User Model
88
159
 
89
160
  ```ruby
90
161
  class User < ActiveRecord::Base
162
+ include TheCommentsUser
163
+
91
164
  # Your implementation of role policy
92
165
  def admin?
93
166
  self == User.first
94
167
  end
95
168
 
96
- # include TheComments methods
97
- include TheCommentsUser
98
-
99
- # denormalization for commentable objects
100
- def commentable_title
101
- login
102
- end
103
-
104
- def commentable_url
105
- [class.to_s.tableize, login].join('/')
106
- end
107
-
108
169
  # Comments moderator checking (simple example)
109
170
  # Usually comment's holder should be moderator
110
171
  def comment_moderator? comment
111
172
  admin? || id == comment.holder_id
112
173
  end
113
-
114
174
  end
115
175
  ```
116
176
 
117
- **User#coments** - comments. Set of all created comments
118
-
119
- ```ruby
120
- User.first.comments
121
- # => Array of comments, where User is creator (owner)
122
- ```
123
-
124
- **User#comcoms** - commentable comments. Set of all comments of all owned commentable objects of this user.
125
-
126
- ```ruby
127
- User.first.comcoms
128
- # => Array of all comments of all owned commentable objects, where User is holder
129
- # Usually comment's holder should be moderator of this comments
130
- # because this user should maintain cleaness of his commentable objects
131
- ```
132
-
133
- **Attention!** You should be sure that you understand who is owner, and who is holder of comments!
134
-
135
- ### Commentable Model (Page, Blog, Article, User ...)
136
-
137
- **Attention!** User model can be commentable object also.
177
+ ### Any Commentable Model (Page, Blog, Article, User(!) ...)
138
178
 
139
179
  ```ruby
140
180
  class Blog < ActiveRecord::Base
141
- # include TheComments methods
142
181
  include TheCommentsCommentable
143
182
 
144
- # (!) Every commentable Model must have next 2 methods
145
- # denormalization for commentable objects
146
183
  def commentable_title
147
- # "My first blog post"
148
- title
184
+ # by default: try(:title) || 'Undefined title'
185
+ # for example: "My first blog post"
186
+ blog_post_name
149
187
  end
150
188
 
151
189
  def commentable_url
152
- # blogs/1-my-first-blog-post
190
+ # by default: ['', self.class.to_s.tableize, self.to_param].join('/')
191
+ # for example: "blogs/1-my-first-blog-post"
153
192
  [self.class.to_s.tableize, slug_id].join('/')
154
193
  end
194
+
195
+ def commentable_state
196
+ # by default: try(:state)
197
+ # for example: "draft"
198
+ self.ban_flag == true ? :banned : :published
199
+ end
155
200
  end
156
201
  ```
157
202
 
@@ -159,7 +204,6 @@ end
159
204
 
160
205
  ```ruby
161
206
  class Comment < ActiveRecord::Base
162
- # include TheComments methods
163
207
  include TheCommentsBase
164
208
 
165
209
  # Define comment's avatar url
@@ -186,27 +230,12 @@ class Comment < ActiveRecord::Base
186
230
  end
187
231
  ```
188
232
 
189
- ### IP, User Agent black lists
190
-
191
- Models must looks like this:
192
-
193
- ```ruby
194
- class IpBlackList < ActiveRecord::Base
195
- include TheCommentsBlackUserAgent
196
- end
197
-
198
- class UserAgentBlackList < ActiveRecord::Base
199
- include TheCommentsBlackIp
200
- end
201
- ```
233
+ ## Using
202
234
 
203
235
  ### Commentable controller
204
236
 
205
237
  ```ruby
206
238
  class BlogsController < ApplicationController
207
- include TheCommentsController::Cookies
208
- include TheCommentsController::ViewToken
209
-
210
239
  def show
211
240
  @blog = Blog.where(id: params[:id]).with_states(:published).first
212
241
  @comments = @blog.comments.with_state([:draft, :published]).nested_set
@@ -220,29 +249,277 @@ end
220
249
  %h1= @blog.title
221
250
  %p= @blog.content
222
251
 
223
- = render partial: 'comments/tree', locals: { comments_tree: @comments, commentable: @blog }
252
+ = render partial: 'the_comments/tree', locals: { commentable: @blog, comments_tree: @comments }
224
253
  ```
225
254
 
226
- ## Configuration
255
+ ## Understanding
256
+
257
+ ### My hopes about comments system
258
+
259
+ * Open comments for everybody (by default). *I hate user registration*
260
+ * Polymorphic comments for any AR Model
261
+ * Threading for comments (can be plain comments list)
262
+ * Cache counters for commentable objects and User
263
+ * Moderation for comments and simple Admin UI
264
+ * Spam traps instead Captcha. *I hate Captcha*
265
+ * Blacklists for IP and UserAgent
266
+ * Denormalization for fast and Request-free Recent comments building
267
+ * Ready for external content filters (<b>sanitize</b>, <b>RedCloth</b>, <b>Markdown</b>)
268
+ * Highlighting and Jumping to comment via anchor
269
+ * Ready for Rails4 (and Rails::Engine)
270
+ * Ready for JQuery 1.9+
271
+ * Delete without destroy
272
+
273
+ ### What's wrong with other gems?
274
+
275
+ Just look at [Ruby-Toolbox](https://www.ruby-toolbox.com/categories/rails_comments). What we can see?
276
+
277
+ * [Acts as commentable with threading](https://github.com/elight/acts_as_commentable_with_threading) - so, guys, where is the render helper for the tree? There is no helper! Should I make render helper for tree by myself? Nooooo!!! I'm so sorry, but I can't use this gem.
278
+ * [acts_as_commentable](https://github.com/jackdempsey/acts_as_commentable) - so, I can see code for models. But I can't see code for controllers and views. Unfortunately, there is no threading. It's not enough for me.
279
+ * [opinio](https://github.com/Draiken/opinio) - looks better, but there is no threading. I want to have more!
280
+ * [has_threaded_comments](https://github.com/aarongough/has_threaded_comments) - Nice work! Nice gem! Models, controllers, views, view helper for tree rendering! **But**, last activity 2 years ago, I need few features, I think - I can make it better.
281
+
282
+ ![TheComments](https://raw.github.com/open-cook/the_comments/master/docs/the_comments.jpg)
227
283
 
228
- **config/initializers/the_comments.rb**
284
+ ## Comments, Posted comments, ComComs
285
+
286
+ ### Posted comments
287
+
288
+ **@user.posted_comments** (has_many)
289
+
290
+ Set of comments, where current user is owner (creator).
229
291
 
230
292
  ```ruby
231
- TheComments.configure do |config|
232
- config.max_reply_depth = 3 # 3 by default
233
- config.tolerance_time = 15 # 5 (sec) by default
234
- config.empty_inputs = [:email, :message, :commentBody] # [:message] by default
235
- end
293
+ @my_comments = @user.posted_comments # => [comment, comment, ...]
294
+
295
+ @comment = @my_comments.first
296
+ @user.id == @comment.user_id # => true
236
297
  ```
237
298
 
238
- * **max_reply_depth** - comments tree nesting by default
239
- * **tolerance_time** - how many seconds user should spend on page, before comment send
240
- * **empty_inputs** - names of hidden (via css) fields for spam detecting
299
+ ### Comments
300
+
301
+ **@commentable.comments** (has_many)
302
+
303
+ Set of comments for this commentable object
304
+
305
+ ```ruby
306
+ @comments = @blog.comments # => [comment, comment, ...]
307
+
308
+ @comment = @comments.first
309
+ @comment.commentable_id == @blog.id # => true
310
+ @comment.commentable_type == 'Blog' # => true
311
+ ```
312
+
313
+ <b>(!) Attention:</b> User Model can be commentable object too!
314
+
315
+ ```ruby
316
+ @comments = @user.comments # => [comment, comment, ...]
317
+
318
+ @comment = @comments.first
319
+ @comment.commentable_id == @user.id # => true
320
+ @comment.commentable_type == 'User' # => true
321
+ ```
322
+
323
+ ### ComComs (COMments of COMmentable objects)
324
+
325
+ **@user.comcoms** (has_many)
326
+
327
+ Set of All <b>COM</b>ments of All <b>COM</b>mentable objects of this User
328
+
329
+ ```ruby
330
+ @comcoms = @user.comcoms # => [comment, comment, ...]
331
+
332
+ @comcom = @comcoms.first
333
+ @user.id == @comcom.holder_id # => true
334
+ ```
335
+
336
+ **Comment#holder_id** should not be empty. Because we should to know, who is moderator of this comment.
337
+
338
+ ```ruby
339
+ @user.id == @comment.holder_id # => true
340
+ # => This user should be MODERATOR for this comment
341
+ ```
342
+
343
+ ## Denormalization
344
+
345
+ For building of Recent comments list (for polymorphic relationship) we need to have many additional requests to database. It's classic problem of polymorphic comments.
346
+
347
+ I use denormalization of commentable objects for solve of this problem.
348
+
349
+ My practice shows - We need 3 denormalized fields into comment for (request-free) building of recent comments list:
350
+
351
+ <img src="https://raw.github.com/open-cook/the_comments/master/docs/the_comments_view_5.gif" alt="the_comments">
352
+
353
+ * **Comment#commentable_title** - for example: "My first post about Ruby On Rails"
354
+ * **Comment#commentable_url** - for example: "/posts/1-my-first-post-about-ruby-on-rails"
355
+ * **Comment#commentable_state** - for example: "draft"
356
+
357
+ That is why any **Commentable Model should have few methods** to provide denormalization for Comments.
358
+
359
+ ## Recent comments building
360
+
361
+ Denormalization makes, building of Recent comments (for polymorphic relationship) is very easy!
362
+
363
+ Controller:
364
+
365
+ ```ruby
366
+ @comments = Comment.with_state(:published)
367
+ .where(commentable_state: [:published])
368
+ .order('created_at DESC')
369
+ .page(params[:page])
370
+ ```
371
+
372
+ View:
373
+
374
+ ```ruby
375
+ - @comments.each do |comment|
376
+ %div
377
+ %p= comment.commentable_title
378
+ %p= link_to comment.commentable_title, comment.commentable_url
379
+ %p= comment.content
380
+ ```
381
+
382
+ ### AntiSpam system
383
+
384
+ **1) Moderation**
385
+
386
+ **2) User agent must have:**
387
+
388
+ * Cookies support
389
+ * JavaScript and Ajax support
390
+
391
+ _Usually spambots not support Cookies and JavaScript_
392
+
393
+ **3) Comment form mast have:**
394
+
395
+ * fake (hidden via css) fields
396
+
397
+ _Usually spambots puts data in fake inputs_
398
+
399
+ **4) Trap via time:**
400
+
401
+ * User should be few seconds on page, before comment sending (by default 5 sec)
402
+
403
+ _Usually spambots works faster, than human. We can try to use this feature of behavior_
404
+
405
+ **5) IP and User Agent blacklists**
406
+
407
+
408
+ ### Strong dependencies of gem
409
+
410
+ ```ruby
411
+ gem 'the_sortable_tree'
412
+ gem 'state_machine'
413
+ ```
414
+
415
+ * **the_sortable_tree** - render helper for nested set
416
+ * **state_machine** - states for moderation and callbacks for recalculating of counters when state of comment was changed
417
+
418
+ ## Customization
419
+
420
+ You can use **generators** for copy files into your Application. After that you can customize almost everything
421
+
422
+ Generators list:
423
+
424
+ ```ruby
425
+ bundle exec rails g the_comments --help
426
+ ```
427
+
428
+ Copy View files for customization:
429
+
430
+ ```ruby
431
+ bundle exec rails g the_comments:views assets
432
+ bundle exec rails g the_comments:views views
433
+ ```
434
+
435
+ Copy Helper file for tree customization:
436
+
437
+ For more info read [TheSortableTree doc](https://github.com/the-teacher/the_sortable_tree)
438
+
439
+ ```ruby
440
+ bundle exec rails g the_comments:views helper
441
+ ```
442
+ ### User methods
443
+
444
+ * @user.<b>posted_comments</b> (all states)
445
+ * @user.<b>my_comments</b> (draft, published)
446
+ * @user.<b>my_comments_count</b>
447
+
448
+ Cache counters methods
449
+
450
+ * @user.<b>recalculate_my_comments_counter!</b>
451
+ * @user.<b>recalculate_comcoms_counters!</b>
452
+
453
+ Comments methods
454
+
455
+ * @user.<b>comments</b>
456
+ * @user.<b>comments_sum</b>
457
+ * @user.<b>draft_comments_count</b>
458
+ * @user.<b>published_comments_count</b>
459
+ * @user.<b>deleted_comments_count</b>
460
+
461
+ Comcoms methods
462
+
463
+ * @user.<b>comcoms</b>
464
+ * @user.<b>comcoms_sum</b>
465
+ * @user.<b>draft_comcoms_count</b>
466
+ * @user.<b>published_comcoms_count</b>
467
+ * @user.<b>deleted_comcoms_count</b>
468
+
469
+ ### Commentable methods
470
+
471
+ * @post.<b>comments</b>
472
+ * @post.<b>draft_comments_count</b>
473
+ * @post.<b>published_comments_count</b>
474
+ * @post.<b>deleted_comments_count</b>
475
+ * @post.<b>comments_sum</b> (draft + published)
476
+ * @post.<b>recalculate_comments_counters!</b>
477
+
478
+ Denornalization methods
479
+
480
+ * @post.<b>commentable_title</b>
481
+ * @post.<b>commentable_url</b>
482
+ * @post.<b>commentable_state</b>
483
+
484
+ ## Online Support
485
+
486
+ I need your opinion, ideas, user experience - that is why you can ask me about this gem via skype: **ilya.killich**
487
+
488
+ ## About author
489
+
490
+ Yes, It's true - I was a school teacher in the past.
491
+ That's why my login is the-teacher.
492
+ Now I'm ruby & frontend developer.
493
+ I learn, I teach, I make a code. And sorry for my English.
241
494
 
242
495
  ## Contributing
243
496
 
244
497
  1. Fork it
245
- 2. Create your feature branch (`git checkout -b my-new-feature`)
246
- 3. Commit your changes (`git commit -am 'Add some feature'`)
247
- 4. Push to the branch (`git push origin my-new-feature`)
248
- 5. Create new Pull Request
498
+ 2. Clone it into local folder
499
+ 3. Add to Gemfile via **gem 'the_comments', path: '/path/to/gem/the_comments'**
500
+ 4. Change code
501
+ 5. git push origin master
502
+ 6. Create pull request via github
503
+
504
+ ### MIT License
505
+
506
+ Copyright (c) 2013 Ilya N. Zykin
507
+
508
+ Permission is hereby granted, free of charge, to any person obtaining
509
+ a copy of this software and associated documentation files (the
510
+ "Software"), to deal in the Software without restriction, including
511
+ without limitation the rights to use, copy, modify, merge, publish,
512
+ distribute, sublicense, and/or sell copies of the Software, and to
513
+ permit persons to whom the Software is furnished to do so, subject to
514
+ the following conditions:
515
+
516
+ The above copyright notice and this permission notice shall be
517
+ included in all copies or substantial portions of the Software.
518
+
519
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
520
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
521
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
522
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
523
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
524
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
525
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.