opinio 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -1,6 +1,8 @@
1
1
  = Opinio
2
2
  {}[http://travis-ci.org/Draiken/opinio.png]
3
3
 
4
+ *IMPORTANT* Version 0.6 might break some behaviour from 0.5 and lower versions, please refer to the {changelog}[https://github.com/Draiken/opinio/blob/master/CHANGELOG.rdoc]
5
+
4
6
  == Description
5
7
 
6
8
  Opinio is an engine used to add comments behaviour to your application.
@@ -16,12 +18,6 @@ and run:
16
18
 
17
19
  bundle
18
20
 
19
- == Documentation
20
-
21
- Rdocs here:
22
- http://rubydoc.info/github/Draiken/opinio/master/frames
23
-
24
-
25
21
  == Usage
26
22
 
27
23
  Opinio provides generators to facilitate it's usage.
@@ -39,19 +35,17 @@ In order to add the comments functionality to a model, you use the *opinio_subje
39
35
  opinio_subjectum
40
36
  end
41
37
 
42
- On the +routes.rb+ you should simply add an +opinio+ for your resource that will have comments
38
+ On the +routes.rb+ you should simply add an +opinio+ for your commentable resource
43
39
 
44
40
  resources :posts do
45
41
  opinio
46
42
  end
47
43
 
48
- If you want to display the comments for the item outside of the resource, you can simply add this to your views:
44
+ To render the comments in your views, there is a helper to display the resource's comments easily:
49
45
 
50
46
  <%= comments_for @post %>
51
47
 
52
- And there you go, you can now comment in your post.
53
-
54
- Alternatively you can render just the comments or just the form like this:
48
+ This will render the comments and a form for new comment submissions. Alternatively you can render just the comments or just the form like this:
55
49
 
56
50
  <%= render_comments @post %>
57
51
  <%= render_comments_form @post %>
@@ -62,7 +56,7 @@ or you can customize it for specific views on the helpers
62
56
 
63
57
  <%= render_comments @post, :page => params[:page], :limit => 5 %>
64
58
 
65
- This can also be used on the +comments_for+ helper.
59
+ This options can also be used on the +comments_for+ helper.
66
60
 
67
61
  == Customization
68
62
 
@@ -75,11 +69,40 @@ Of course you will want to customize how the comments are displayed or any other
75
69
  And you can customize all the views used by the engine.
76
70
 
77
71
  === Behaviour
72
+ ==== Opinio Model
73
+
74
+ You can customize the opinio model to suit your needs. The basic customization is the owner class name. It defaults to +User+ but you can change that in the initializer or in the model by passing the +:owner_class_name => "MyOwnerClass"+ option to the +opinio_model+ method call.
75
+
76
+ Another customization you can do is set the +counter_cache+ to true in the commentable model. You can use the +:counter_cache+ option for that.
77
+
78
+ The other two customizations are only made through the initializer, and they are the +accept_replies+ which defaults to true and +strip_html_tags_on_save+ which also defaults to true.
79
+
80
+ Validations on the opinio model are very basic, just ensuring it has a body, a commentable and an owner, if you want any other kind of validation, like the minimum size of a comment, you can use the regular AR validations as you wish.
81
+
82
+ Remember that if you use titles, you need to add that to your comments table, since the generator doesn't add it by default.
83
+
84
+ ==== Opinio Subjectum
85
+
86
+ To change how the models that actually have the comments, you can customize them with any option you would use to a regular +has_many+ relationship in ActiveRecord.
87
+
88
+ The default options are these:
89
+
90
+ has_many :comments,
91
+ :class_name => Opinio.model_name,
92
+ :as => :commentable,
93
+ :order => "created_at #{Opinio.sort_order}"),
94
+ :dependent => :destroy
95
+
96
+ The +sort_order+ and +model_name+ are both setup in the initializer. Here you can do things like, let's say you have moderation in your comments, you can only show the approved comments:
97
+
98
+ opinio_subjectum :conditions => ["approved = ?", true]
99
+
100
+ Remember you can override any of these options (except +as+) by passing them to the +opinio_subjectum+ method.
78
101
 
79
102
  ==== Pretty Urls
80
103
 
81
104
  Often times you will want the engine to show the index of comments for a specific item
82
- without having to pass *:commentable_type* or *:commentable_id*.
105
+ without having to pass the *:commentable_type* or *:commentable_id* parameters.
83
106
 
84
107
  In order to do that, opinio provides a method to *ActionController::Base*:
85
108
 
@@ -102,10 +125,10 @@ I suggest you put this method on the *ApplicationController*
102
125
 
103
126
  ==== Customize destroy conditions
104
127
 
105
- By default, anyone can destroy any comment in the engine. We don't want that.
106
- To setup a custom destroy condition we can use the methods provided by opinio
128
+ By default, noone can destroy a comment in the engine. You have to tell the engine who can do it.
129
+ To setup a custom destroy condition use the methods provided by opinio
107
130
  in our controllers. For instance, if our opinio model is called 'comment'
108
- it would be like this:
131
+ it could be written like this:
109
132
 
110
133
  comment_destroy_conditions do |comment|
111
134
  comment.owner == current_user
@@ -143,7 +166,6 @@ For issues please use the github {issues tracker}[https://github.com/Draiken/opi
143
166
 
144
167
  === TODO
145
168
 
146
- * Better controller overriding (coding and documentation)
147
- * Support for deeper levels of replies
148
169
  * Refactor the +comments_for+ helper
149
170
  * Extract documentation to wiki
171
+ * Add mongoid support
@@ -21,7 +21,7 @@ class Opinio::CommentsController < ApplicationController
21
21
  format.js
22
22
  format.html do
23
23
  set_flash(flash_area, message)
24
- redirect_to(resource.is_a?(Opinio.model_name.constantize) ? resource.commentable : resource)
24
+ redirect_to(opinio_after_create_path(resource))
25
25
  end
26
26
  end
27
27
  end
@@ -40,7 +40,7 @@ class Opinio::CommentsController < ApplicationController
40
40
 
41
41
  respond_to do |format|
42
42
  format.js
43
- format.html { redirect_to( @comment.commentable ) }
43
+ format.html { redirect_to( opinio_after_destroy_path(@comment) ) }
44
44
  end
45
45
  end
46
46
 
@@ -7,6 +7,10 @@ module Opinio
7
7
  require 'opinio/controllers/replies'
8
8
  end
9
9
 
10
+ require 'opinio/railtie'
11
+ require 'opinio/rails'
12
+ require 'opinio/orm/active_record'
13
+
10
14
  mattr_accessor :model_name
11
15
  @@model_name = "Comment"
12
16
 
@@ -26,7 +30,7 @@ module Opinio
26
30
  @@interval_between_comments = false
27
31
 
28
32
  mattr_accessor :destroy_conditions
29
- @@destroy_conditions = Proc.new { true }
33
+ @@destroy_conditions = Proc.new { false }
30
34
 
31
35
  mattr_accessor :current_user_method
32
36
  @@current_user_method = :current_user
@@ -53,14 +57,10 @@ module Opinio
53
57
  end
54
58
 
55
59
  def self.check_custom_identifiers(params)
56
- self.custom_identifiers.each do |idf|
57
- ret = idf.call(params)
58
- return ret unless ret.nil?
60
+ self.custom_identifiers.each do |identifier|
61
+ identified = identifier.call(params)
62
+ return identified unless identified.nil?
59
63
  end
60
64
  nil
61
65
  end
62
-
63
- require File.join(File.dirname(__FILE__), 'opinio', 'railtie')
64
- require File.join(File.dirname(__FILE__), 'opinio', 'rails')
65
- require File.join(File.dirname(__FILE__), 'opinio', 'orm', 'active_record')
66
66
  end
@@ -25,6 +25,14 @@ module Opinio
25
25
  def can_destroy_opinio?(opinio)
26
26
  self.instance_exec(opinio, &Opinio.destroy_conditions)
27
27
  end
28
+
29
+ def opinio_after_create_path(resource)
30
+ resource.is_a?(Opinio.model_name.constantize) ? resource.commentable : resource
31
+ end
32
+
33
+ def opinio_after_destroy_path(comment)
34
+ comment.commentable
35
+ end
28
36
  end
29
37
  end
30
38
  end
@@ -1,3 +1,5 @@
1
+ require 'opinio/opinio_model/validations'
2
+
1
3
  module Opinio
2
4
  module OpinioModel
3
5
 
@@ -9,73 +11,45 @@ module Opinio
9
11
 
10
12
  # Adds the Opinio functionallity to the model
11
13
  # You can pass a hash of options to customize the Opinio model
12
- #
13
- # === Options
14
- #
15
- # [:belongs_to]
16
- # You can specify the class that owns the comments on
17
- # +config/initializers/opinio.rb+
18
- # but you can also pass it explicitly here:
19
- # eg. <tt>:belongs_to => "Admin"</tt>
20
- # [:counter_cache]
21
- # Customize the counter cache here, defaults to false
22
- # [:body_length]
23
- # You can pass a <tt>Range</tt> to determine the size of the body that will be
24
- # validated
25
- # [:title_length]
26
- # If you are using titles in your opinio model (set on the
27
- # initializer) you can pass a <tt>Range</tt> so it is validated.
28
14
  def opinio(*args)
29
- return if self.included_modules.include?(Opinio::OpinioModel::InstanceMethods)
15
+ return if self.included_modules.include?(Opinio::OpinioModel::Validations)
30
16
  options = args.extract_options!
31
17
 
32
18
  if Opinio.use_title
33
19
  attr_accessible :title
34
- validates :title,
35
- {:presence => true}.merge( :length => options[:title_length] )
36
20
  end
37
21
  attr_accessible :body
38
22
 
39
- commentable_options = { :polymorphic => true }
40
- if options[:counter_cache]
41
- commentable_options.merge!(:counter_cache => options[:counter_cache])
42
- end
43
-
44
- belongs_to :commentable, commentable_options
45
- belongs_to :owner, :class_name => options.reverse_merge(:belongs_to => Opinio.owner_class_name)[:belongs_to]
46
-
47
- #TODO: refactor this
48
- if Opinio.interval_between_comments
49
- validate :last_comment_time, :if => :new_record?
50
- cattr_accessor :comments_interval
51
- self.comments_interval = options.reverse_merge(:time => Opinio.interval_between_comments)[:time]
52
- end
53
-
54
- extra_options = {}
55
- if options[:body_length]
56
- extra_options = { :length => options[:body_length] }
57
- end
58
-
59
- validates :body,
60
- { :presence => true }.reverse_merge(extra_options)
61
-
62
- validates_presence_of :commentable
63
-
64
- validates :owner, :presence => true, :associated => true
23
+ belongs_to :commentable, :polymorphic => true, :counter_cache => options.fetch(:counter_cache, false)
24
+ belongs_to :owner, :class_name => options.fetch(:owner_class_name, Opinio.owner_class_name)
65
25
 
66
26
  scope :owned_by, lambda {|owner| where('owner_id = ?', owner.id) }
67
27
 
68
- send :include, Opinio::OpinioModel::InstanceMethods
28
+ send :include, Opinio::OpinioModel::Validations
69
29
 
70
30
  if Opinio.accept_replies
71
31
  send :include, RepliesSupport
72
32
  end
73
33
 
74
34
  if Opinio.strip_html_tags_on_save
35
+ send :include, Sanitizing
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+ module Sanitizing
42
+ def self.included(base)
43
+ base.class_eval do
75
44
  send :include, ActionView::Helpers::SanitizeHelper
76
45
  before_save :strip_html_tags
77
46
  end
47
+ end
48
+
49
+ private
78
50
 
51
+ def strip_html_tags
52
+ self.body = strip_tags(self.body)
79
53
  end
80
54
  end
81
55
 
@@ -84,28 +58,9 @@ module Opinio
84
58
  base.validate :cannot_be_comment_of_a_comments_comment
85
59
  base.opinio_subjectum :order => 'created_at ASC'
86
60
  end
87
- end
88
-
89
- module InstanceMethods
90
61
 
91
62
  private
92
63
 
93
- # Checks the time of the last comment
94
- # made by the same owner
95
- def last_comment_time
96
- last_comment = Comment.owned_by(self.owner).order('created_at DESC').last
97
- if last_comment
98
- if (Time.now - last_comment.created_at).round >= self.comments_interval
99
- true
100
- else
101
- errors.add(:created_at, I18n.translate('opinio.messages.comment_interval', :time => self.comments_interval))
102
- false
103
- end
104
- else
105
- true
106
- end
107
- end
108
-
109
64
  # Validates that you cannot comment on a comment's comment
110
65
  def cannot_be_comment_of_a_comments_comment
111
66
  if new_record? && self.commentable_type == Opinio.model_name
@@ -115,10 +70,6 @@ module Opinio
115
70
  end
116
71
  end
117
72
 
118
- def strip_html_tags
119
- self.body = strip_tags(self.body)
120
- end
121
-
122
73
  end
123
74
  end
124
75
  end
@@ -0,0 +1,50 @@
1
+ module Opinio
2
+ module OpinioModel
3
+ module Validations
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+
9
+ #TODO: refactor this
10
+ if Opinio.interval_between_comments
11
+ include Opinio::OpinioModel::Validations::IntervalMethods
12
+ validate :validate_last_comment_time, :if => :new_record?
13
+ cattr_accessor :comments_interval
14
+ self.comments_interval = options.reverse_merge(:time => Opinio.interval_between_comments)[:time]
15
+ end
16
+
17
+ validates :body, :presence => true
18
+ validates :commentable, :presence => true
19
+ validates :owner, :presence => true, :associated => true
20
+
21
+ end
22
+
23
+
24
+ module IntervalMethods
25
+
26
+ private
27
+
28
+ # Checks the time of the last comment
29
+ # made by the same owner
30
+ def validate_last_comment_time
31
+ last_comment = Comment.owned_by(self.owner).order('created_at DESC').last
32
+ if last_comment
33
+ if (Time.now - last_comment.created_at).round >= self.comments_interval
34
+ true
35
+ else
36
+ errors.add(:created_at,
37
+ I18n.translate('opinio.messages.comment_interval',
38
+ :time => self.comments_interval))
39
+ false
40
+ end
41
+ else
42
+ true
43
+ end
44
+ end
45
+
46
+ end # IntervalMethods
47
+
48
+ end # Validations
49
+ end # OpinioModel
50
+ end # Opinio
@@ -2,27 +2,23 @@ module Opinio
2
2
  module OpinioSubjectum
3
3
 
4
4
  def self.included(base)
5
- base.extend ClassMethods
5
+ base.extend(ClassMethods)
6
6
  end
7
7
 
8
8
  module ClassMethods
9
9
  def opinio_subjectum(*args)
10
10
  options = args.extract_options!
11
+ options.delete(:as)
11
12
 
12
- has_many :comments,
13
- :class_name => Opinio.model_name,
14
- :as => :commentable,
15
- :order => options.reverse_merge(:order => "created_at #{Opinio.sort_order}")[:order],
16
- :dependent => :destroy
13
+ default_options = { :class_name => Opinio.model_name,
14
+ :as => :commentable,
15
+ :order => "created_at #{Opinio.sort_order}",
16
+ :dependent => :destroy }
17
17
 
18
+ has_many :comments, default_options.merge(options)
18
19
 
19
- send :include, Opinio::OpinioSubjectum::InstanceMethods
20
20
  end
21
21
  end
22
22
 
23
- module InstanceMethods
24
-
25
- end
26
-
27
23
  end
28
24
  end
@@ -45,6 +45,34 @@ shared_examples_for :opinio do
45
45
  c.save.should == false
46
46
  end
47
47
 
48
+ context "when strip_html_tags_on_save is true" do
49
+ it "should strip html tags" do
50
+ comment = create_valid_comment('<h1>Chuck will save us!</h1>')
51
+ comment.body.should == 'Chuck will save us!'
52
+ end
53
+ end
54
+
55
+ context "when strip_html_tags_on_save is false" do
56
+
57
+ # we have to create a different class
58
+ # because opinio adds the strip tags callbacks
59
+ # only once when opinio is called on the class
60
+ class NoSanitizerComment < ActiveRecord::Base
61
+ self.table_name = :comments
62
+ end
63
+
64
+ before do
65
+ Opinio.stub(:strip_html_tags_on_save).and_return(false)
66
+ NoSanitizerComment.class_eval do
67
+ opinio
68
+ end
69
+ end
70
+ it "should not strip html tags" do
71
+ comment = create_valid_comment('<h1>Chuck will save us!</h1>', NoSanitizerComment)
72
+ comment.body.should == '<h1>Chuck will save us!</h1>'
73
+ end
74
+ end
75
+
48
76
  end
49
77
 
50
78
 
@@ -1,5 +1,5 @@
1
1
  module Opinio
2
2
  class Version
3
- VERSION = '0.5'
3
+ VERSION = '0.6'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opinio
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.5'
4
+ version: '0.6'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-26 00:00:00.000000000Z
12
+ date: 2012-09-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &2164731680 !ruby/object:Gem::Requirement
16
+ requirement: &70264667294060 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2164731680
24
+ version_requirements: *70264667294060
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: kaminari
27
- requirement: &2164881320 !ruby/object:Gem::Requirement
27
+ requirement: &70264667286540 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2164881320
35
+ version_requirements: *70264667286540
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: jquery-rails
38
- requirement: &2165159760 !ruby/object:Gem::Requirement
38
+ requirement: &70264667281340 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2165159760
46
+ version_requirements: *70264667281340
47
47
  description: Opinio is an engine used to add comments functionallity to rails 3 applications.
48
48
  email:
49
49
  - luiz.felipe.gp@gmail.com
@@ -72,6 +72,7 @@ files:
72
72
  - lib/opinio/controllers/helpers.rb
73
73
  - lib/opinio/controllers/internal_helpers.rb
74
74
  - lib/opinio/controllers/replies.rb
75
+ - lib/opinio/opinio_model/validations.rb
75
76
  - lib/opinio/opinio_model.rb
76
77
  - lib/opinio/opinio_subjectum.rb
77
78
  - lib/opinio/orm/active_record.rb
@@ -85,8 +86,7 @@ files:
85
86
  - config/locales/opinio.en.yml
86
87
  - MIT-LICENSE
87
88
  - Rakefile
88
- - Gemfile-rails-3.0.x
89
- - Gemfile-rails-3.1.x
89
+ - Gemfile
90
90
  - README.rdoc
91
91
  homepage:
92
92
  licenses: []
@@ -1,29 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec
4
-
5
- gem "kaminari"
6
- gem "rails", ">= 3.1"
7
- gem "sqlite3"
8
- gem "jquery-rails"
9
-
10
- group :development do
11
- gem "ruby-debug19" if RUBY_VERSION == '1.9.2'
12
- gem 'guard-rspec'
13
- if RUBY_PLATFORM =~ /darwin/i
14
- gem 'rb-fsevent'
15
- gem 'growl'
16
- end
17
- end
18
-
19
- group :test do
20
- gem "cucumber"
21
- gem "cucumber-rails"
22
- gem "capybara"
23
- gem "launchy"
24
- gem "database_cleaner"
25
- gem "rspec-rails"
26
- end
27
- # To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
28
- # gem 'ruby-debug'
29
- # gem 'ruby-debug19'