opinio 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +24 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +127 -0
- data/Rakefile +28 -0
- data/app/controllers/opinio/comments_controller.rb +33 -0
- data/app/views/opinio/comments/_comment.html.erb +15 -0
- data/app/views/opinio/comments/_comments.html.erb +15 -0
- data/app/views/opinio/comments/_new.html.erb +18 -0
- data/app/views/opinio/comments/create.js.erb +11 -0
- data/app/views/opinio/comments/destroy.js.erb +3 -0
- data/app/views/opinio/comments/index.html.erb +7 -0
- data/app/views/opinio/comments/reply.js.erb +3 -0
- data/lib/generators/opinio/install/install_generator.rb +34 -0
- data/lib/generators/opinio/install/templates/initializers/opinio.erb +8 -0
- data/lib/generators/opinio/install/templates/migrations/create_model.rb +13 -0
- data/lib/generators/opinio/install/templates/models/model.rb +3 -0
- data/lib/generators/opinio/views/views_generator.rb +13 -0
- data/lib/opinio.rb +55 -0
- data/lib/opinio/controllers/extensions.rb +27 -0
- data/lib/opinio/controllers/helpers.rb +22 -0
- data/lib/opinio/controllers/internal_helpers.rb +33 -0
- data/lib/opinio/controllers/replies.rb +23 -0
- data/lib/opinio/opinio_model.rb +112 -0
- data/lib/opinio/opinio_subjectum.rb +28 -0
- data/lib/opinio/orm/active_record.rb +19 -0
- data/lib/opinio/rails.rb +8 -0
- data/lib/opinio/rails/routes.rb +20 -0
- data/lib/opinio/railtie.rb +22 -0
- data/lib/opinio/schema.rb +21 -0
- data/lib/opinio/version.rb +5 -0
- metadata +77 -0
data/Gemfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem "kaminari"
|
6
|
+
gem "rails", "~> 3.0.4"
|
7
|
+
gem "sqlite3"
|
8
|
+
gem "jquery-rails"
|
9
|
+
|
10
|
+
group :development do
|
11
|
+
gem "ruby-debug19"
|
12
|
+
end
|
13
|
+
|
14
|
+
group :test do
|
15
|
+
gem "cucumber"
|
16
|
+
gem "cucumber-rails"
|
17
|
+
gem "capybara"
|
18
|
+
gem "launchy"
|
19
|
+
gem "database_cleaner"
|
20
|
+
gem "rspec-rails"
|
21
|
+
end
|
22
|
+
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
|
23
|
+
# gem 'ruby-debug'
|
24
|
+
# gem 'ruby-debug19'
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
= Opinio
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
Opinio is an engine used to add comments behaviour to your application.
|
6
|
+
The engine is designed to work only with *Rails 3*
|
7
|
+
|
8
|
+
== Intallation
|
9
|
+
|
10
|
+
Simply add the following line to your *Gemfile*:
|
11
|
+
|
12
|
+
gem "opinio"
|
13
|
+
|
14
|
+
and run:
|
15
|
+
|
16
|
+
bundle
|
17
|
+
|
18
|
+
== Documentation
|
19
|
+
|
20
|
+
Rdocs here:
|
21
|
+
http://rubydoc.info/github/Draiken/opinio/master/frames
|
22
|
+
|
23
|
+
|
24
|
+
== Usage
|
25
|
+
|
26
|
+
Opinio provides generators to facilitate it's usage.
|
27
|
+
The most common way to quickly get Opinio working is:
|
28
|
+
|
29
|
+
rails g opinio:install comment
|
30
|
+
|
31
|
+
This will generate the *Comment* model, migration and also generate the opinio initializer for customization of the engine.
|
32
|
+
A `opinio_model` will be added on the `routes.rb`. This method adds the default urls for the model that will acts as the comment
|
33
|
+
|
34
|
+
In order to add the comments functionallity to a model, you use the *opinio_subjectum* method
|
35
|
+
|
36
|
+
class Post < ActiveRecord::Base
|
37
|
+
opinio_subjectum
|
38
|
+
end
|
39
|
+
|
40
|
+
On the `routes.rb` you should simply add an `opinio` for your resource that will have comments
|
41
|
+
|
42
|
+
resources :posts do
|
43
|
+
opinio
|
44
|
+
end
|
45
|
+
|
46
|
+
If you want to display the comments for the item outside of the resource, you can simply add this to your views:
|
47
|
+
|
48
|
+
<%= comments_for @post %>
|
49
|
+
|
50
|
+
And there you go, you can now comment in your post.
|
51
|
+
Aditional options can be found on the {RDocs}[http://rubydoc.info/github/Draiken/opinio/master/frames]
|
52
|
+
|
53
|
+
== Customization
|
54
|
+
|
55
|
+
=== Views
|
56
|
+
|
57
|
+
Of course you will want to customize how the comments are displayed or any other customization to the view. To generate the view files on your application, run:
|
58
|
+
|
59
|
+
rails g opinio:views
|
60
|
+
|
61
|
+
And you can customize all the views used by the engine.
|
62
|
+
|
63
|
+
=== Behaviour
|
64
|
+
|
65
|
+
==== Pretty Urls
|
66
|
+
|
67
|
+
Often times you will want the engine to show the index of comments for a specific item
|
68
|
+
without having to pass *:commentable_type* or *:commentable_id*.
|
69
|
+
|
70
|
+
In order to do that, opinio provides a method to *ActionController::Base*:
|
71
|
+
|
72
|
+
opinio_identifier do |params|
|
73
|
+
next Review.find(params[:review_id]) if params[:review_id]
|
74
|
+
next Product.find(params[:product_id]) if params[:product_id]
|
75
|
+
end
|
76
|
+
|
77
|
+
Note: you use next instead of return because it is a proc that will be executed later on, and you cannot return on procs
|
78
|
+
|
79
|
+
Basically on this method you receive the *params* variable and you tell the engine, who owns
|
80
|
+
the comments from that page.
|
81
|
+
This allows you to use routes like:
|
82
|
+
|
83
|
+
/products/1/comments
|
84
|
+
/products/1/reviews/1/comments
|
85
|
+
|
86
|
+
Without passing those 2 parameters.
|
87
|
+
I suggest you put this method on the *ApplicationController*
|
88
|
+
|
89
|
+
==== Customize destroy conditions
|
90
|
+
|
91
|
+
By default, anyone can destroy any comment in the engine. We don't want that.
|
92
|
+
To setup a custom destroy condition we can use the methods provided by opinio
|
93
|
+
in our controllers. For instance, if our opinio model is called 'comment'
|
94
|
+
it would be like this:
|
95
|
+
|
96
|
+
comment_destroy_conditions do |comment|
|
97
|
+
comment.owner == current_user
|
98
|
+
end
|
99
|
+
|
100
|
+
This would make users only be able to remove their own comments.
|
101
|
+
Another example would be using the *CanCan*:
|
102
|
+
|
103
|
+
comment_destroy_conditions do |comment|
|
104
|
+
authorize :destroy, comment
|
105
|
+
end
|
106
|
+
|
107
|
+
You get the picture, you're inside your controller's methods on that block
|
108
|
+
so you can call anything your normal controllers call on actions.
|
109
|
+
|
110
|
+
== Contribution
|
111
|
+
|
112
|
+
If you want to help in any way with *Opinio* please message me or fork the project, make the changes and send me a pull request.
|
113
|
+
For issues please use the github {issues tracker}[https://github.com/Draiken/opinio/issues]
|
114
|
+
|
115
|
+
Remember this engine is still in development :)
|
116
|
+
|
117
|
+
=== TODO
|
118
|
+
|
119
|
+
* Haml views
|
120
|
+
* Better controller overriding (coding and documentation)
|
121
|
+
* Support for deeper levels of replies
|
122
|
+
* Refactor the `comments_for` helper
|
123
|
+
* Extract documentation to wiki
|
124
|
+
* Add tons of rspecs for
|
125
|
+
* controllers
|
126
|
+
* routes
|
127
|
+
* model extensions
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'rubygems'
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
require 'rake/rdoctask'
|
11
|
+
|
12
|
+
require 'cucumber'
|
13
|
+
require 'cucumber/rake/task'
|
14
|
+
|
15
|
+
require 'rspec/core'
|
16
|
+
require 'rspec/core/rake_task'
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new(:spec)
|
19
|
+
|
20
|
+
task :default => :spec
|
21
|
+
|
22
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
23
|
+
rdoc.rdoc_dir = 'rdoc'
|
24
|
+
rdoc.title = 'Opinio'
|
25
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
26
|
+
rdoc.rdoc_files.include('README.rdoc')
|
27
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Opinio::CommentsController < ApplicationController
|
2
|
+
include Opinio::Controllers::InternalHelpers
|
3
|
+
include Opinio::Controllers::Replies if Opinio.accept_replies
|
4
|
+
|
5
|
+
def index
|
6
|
+
@comments = resource.comments.page(params[:page])
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
@comment = resource.comments.build(params[:comment])
|
11
|
+
@comment.owner = current_user
|
12
|
+
if @comment.save
|
13
|
+
flash[:notice] = I18n.translate('opinio.comment.sent', :default => "Comment sent successfully.")
|
14
|
+
else
|
15
|
+
flash[:error] = I18n.translate('opinio.comment.error', :default => "Error sending the comment.")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def destroy
|
20
|
+
@comment = Opinio.model_name.constantize.find(params[:id])
|
21
|
+
|
22
|
+
if can_destroy_opinio?(@comment)
|
23
|
+
@comment.destroy
|
24
|
+
flash[:notice] = I18n.translate('opinio.comment.destroyed', :default => "Comment removed successfully")
|
25
|
+
else
|
26
|
+
#flash[:error] = I18n.translate('opinio.comment.not_permitted', :default => "Not permitted")
|
27
|
+
logger.warning "user #{current_user.email} tried to remove a comment from another user #{@comment.owner.email}"
|
28
|
+
render :text => "unauthorized", :status => 401
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% reply = defined?(reply) ? reply : false %>
|
2
|
+
<li id="comment_<%= comment.id %>">
|
3
|
+
<span>User: <%= comment.owner.id %></span>
|
4
|
+
<p>
|
5
|
+
<%= comment.body %>
|
6
|
+
</p>
|
7
|
+
<%= link_to 'Destroy', comment_path(comment), :method => :delete, :remote => true %>
|
8
|
+
<%# this enables only 1 level of replies %>
|
9
|
+
<% if Opinio.accept_replies && !reply %>
|
10
|
+
<span><%= link_to t("opinio.reply", :default => "Reply"), reply_comment_path(comment), :remote => true %></span>
|
11
|
+
<ul id="comment_<%= comment.id %>_replies" class="replies">
|
12
|
+
<%= render :partial => "opinio/comments/comment", :collection => comment.comments, :locals => {:reply => true} %>
|
13
|
+
</ul>
|
14
|
+
<% end %>
|
15
|
+
</li>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<div>
|
2
|
+
<%= paginate comments %>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<ul id="comments">
|
6
|
+
<% unless comments.empty? %>
|
7
|
+
<%= render :partial => 'opinio/comments/comment', :collection => comments %>
|
8
|
+
<% else %>
|
9
|
+
<li id="no_comments"><%= t 'opinio.no_comments_found', :default => "No comments found" %></li>
|
10
|
+
<% end %>
|
11
|
+
</ul>
|
12
|
+
|
13
|
+
<div>
|
14
|
+
<%= paginate comments %>
|
15
|
+
</div>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<div id="new_comment">
|
2
|
+
<% if current_user %>
|
3
|
+
<h2>Send Comments</h3>
|
4
|
+
<%= form_for Comment.new, :remote => true do |f| %>
|
5
|
+
<p>
|
6
|
+
<%= f.label :body, "Comment" %>
|
7
|
+
<%= f.text_area :body %>
|
8
|
+
</p>
|
9
|
+
<%= hidden_field_tag :commentable_id, commentable.id %>
|
10
|
+
<%= hidden_field_tag :commentable_type, commentable.class.base_class.name.to_s %>
|
11
|
+
<%= f.submit "Send Comment" %>
|
12
|
+
<% end %>
|
13
|
+
<% else %>
|
14
|
+
<p>
|
15
|
+
Must be logged in to comment.
|
16
|
+
</p>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
jQuery('#no_comments').fadeOut()
|
2
|
+
<% if @reply %>
|
3
|
+
if(jQuery('#comment_<%= @comment.commentable_id %> ul').length == 0)
|
4
|
+
jQuery('#comment_<%= @comment.commentable_id %>').append('<ul id="comment_<%= @comment.commentable_id %>_replies" class="replies"></ul>')
|
5
|
+
jQuery('#comment_<%= @comment.commentable_id %>_replies').append("<%= escape_javascript( render @comment, :locals => {:reply => @reply} ) %>")
|
6
|
+
jQuery('#commentable_id').val('<%= @comment.commentable.commentable_id %>')
|
7
|
+
jQuery('#commentable_type').val('<%= @comment.commentable.commentable_type %>')
|
8
|
+
<% else %>
|
9
|
+
jQuery('#comments').prepend("<%= escape_javascript( render @comment, :locals => {:reply => @reply} ) %>")
|
10
|
+
<% end %>
|
11
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::NamedBase
|
4
|
+
include Rails::Generators::Migration
|
5
|
+
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
|
8
|
+
|
9
|
+
def generate_model
|
10
|
+
template "models/model.rb", "app/models/#{file_name}.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate_migration
|
14
|
+
migration_template "migrations/create_model.rb", "db/migrate/create_#{table_name}", {:assigns => {:name => name, :table_name => table_name}}
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_initializer
|
18
|
+
template "initializers/opinio.erb", "config/initializers/opinio.rb"
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_route
|
22
|
+
route "opinio_model"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.next_migration_number(dirname)
|
26
|
+
if ActiveRecord::Base.timestamped_migrations
|
27
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
28
|
+
else
|
29
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/opinio.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Opinio
|
2
|
+
#autoload :Railtie, 'opinio/railtie'
|
3
|
+
autoload :Schema, 'opinio/schema'
|
4
|
+
|
5
|
+
module Controllers
|
6
|
+
autoload :Helpers, 'opinio/controllers/helpers'
|
7
|
+
autoload :InternalHelpers, 'opinio/controllers/internal_helpers'
|
8
|
+
autoload :Replies, 'opinio/controllers/replies'
|
9
|
+
end
|
10
|
+
|
11
|
+
mattr_accessor :model_name
|
12
|
+
@@model_name = "Comment"
|
13
|
+
|
14
|
+
mattr_accessor :owner_class_name
|
15
|
+
@@owner_class_name = "User"
|
16
|
+
|
17
|
+
mattr_accessor :use_title
|
18
|
+
@@use_title = false
|
19
|
+
|
20
|
+
mattr_accessor :accept_replies
|
21
|
+
@@accept_replies = false
|
22
|
+
|
23
|
+
mattr_accessor :custom_identifiers
|
24
|
+
@@custom_identifiers = Array.new
|
25
|
+
|
26
|
+
mattr_accessor :interval_between_comments
|
27
|
+
@@interval_between_comments = false
|
28
|
+
|
29
|
+
mattr_accessor :destroy_conditions
|
30
|
+
@@destroy_conditions = Proc.new { true }
|
31
|
+
|
32
|
+
def self.setup
|
33
|
+
yield self
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.opinio_identifier(block)
|
37
|
+
@@custom_identifiers << block
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.set_destroy_conditions(&block)
|
41
|
+
@@destroy_conditions = block
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.check_custom_identifiers(params)
|
45
|
+
self.custom_identifiers.each do |idf|
|
46
|
+
ret = idf.call(params)
|
47
|
+
return ret unless ret.nil?
|
48
|
+
end
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
require File.join(File.dirname(__FILE__), 'opinio', 'railtie')
|
53
|
+
require File.join(File.dirname(__FILE__), 'opinio', 'rails')
|
54
|
+
require File.join(File.dirname(__FILE__), 'opinio', 'orm', 'active_record')
|
55
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Controllers
|
3
|
+
module Extensions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
(class << self; self; end).instance_eval do
|
8
|
+
define_method "#{Opinio.model_name.underscore}_destroy_conditions" do |&block|
|
9
|
+
Opinio.set_destroy_conditions( &block )
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def opinio_identifier(&block)
|
16
|
+
Opinio.opinio_identifier(block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
def can_destroy_opinio?(opinio)
|
22
|
+
self.instance_exec(opinio, &Opinio.destroy_conditions)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Controllers
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def comments_for(object, options = {})
|
6
|
+
render_comments(object, options) +
|
7
|
+
( render_comments_form(object, options) unless options[:no_new] ).to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_comments(object, options = {})
|
11
|
+
limit = options.delete(:limit) || Opinio.model_name.constantize.default_per_page
|
12
|
+
render( :partial => "opinio/comments/comments", :locals => {:comments => object.comments.page(1).limit(limit), :commentable => object, :options => options} )
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_comments_form(object, options = {})
|
16
|
+
render( :partial => "opinio/comments/new", :locals => {:commentable => object, :options => options} )
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Controllers
|
3
|
+
module InternalHelpers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
helper_method :resource, :resource_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def resource
|
11
|
+
@resource ||= custom_resource_identifier(params) || resource_by_params
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource_by_params
|
15
|
+
if params[:commentable_type]
|
16
|
+
params[:commentable_type].constantize.find(params[:commentable_id])
|
17
|
+
elsif params[:comment]
|
18
|
+
params[:comment][:commentable_type].constantize.find(params[:comment][:commentable_id])
|
19
|
+
else
|
20
|
+
raise "Unable to determine comments holder"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def custom_resource_identifier(params)
|
25
|
+
Opinio.check_custom_identifiers(params)
|
26
|
+
end
|
27
|
+
|
28
|
+
def resource_name
|
29
|
+
Opinio.model_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Controllers
|
3
|
+
module Replies
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before_filter :check_reply, :only => [:create]
|
8
|
+
end
|
9
|
+
|
10
|
+
def reply
|
11
|
+
@commentable_type = Opinio.model_name
|
12
|
+
@commentable_id = params[:id]
|
13
|
+
@commentable = Opinio.model_name.constantize.find(params[:id])
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_reply
|
19
|
+
@reply = params[:commentable_type] == Opinio.model_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Opinio
|
2
|
+
module OpinioModel
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# Adds the Opinio functionallity to the model
|
11
|
+
# 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
|
+
def opinio(*args)
|
29
|
+
return if self.included_modules.include?(Opinio::OpinioModel::InstanceMethods)
|
30
|
+
options = args.extract_options!
|
31
|
+
|
32
|
+
if Opinio.use_title
|
33
|
+
attr_accessible :title
|
34
|
+
validates :title,
|
35
|
+
{}.merge( :length => options[:title_length] )
|
36
|
+
end
|
37
|
+
attr_accessible :body
|
38
|
+
|
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
|
+
scope :owned_by, lambda {|owner| where('owner_id = ?', owner.id) }
|
65
|
+
|
66
|
+
send :include, Opinio::OpinioModel::InstanceMethods
|
67
|
+
|
68
|
+
if Opinio.accept_replies
|
69
|
+
validate :cannot_be_comment_of_a_comments_comment
|
70
|
+
opinio_subjectum :order => 'created_at ASC'
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module InstanceMethods
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# Checks the time of the last comment
|
81
|
+
# made by the same owner
|
82
|
+
def last_comment_time
|
83
|
+
last_comment = Comment.owned_by(self.owner).order('created_at DESC').last
|
84
|
+
if last_comment
|
85
|
+
if (Time.now - last_comment.created_at).round >= self.comments_interval
|
86
|
+
true
|
87
|
+
else
|
88
|
+
errors.add(
|
89
|
+
:created_at,
|
90
|
+
I18n.t('opinio.comment_interval',
|
91
|
+
:time => self.comments_interval,
|
92
|
+
:default => "You must wait %{time} seconds to comment again.")
|
93
|
+
)
|
94
|
+
false
|
95
|
+
end
|
96
|
+
else
|
97
|
+
true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Validates that you cannot comment on a comment's comment
|
102
|
+
def cannot_be_comment_of_a_comments_comment
|
103
|
+
if new_record? && self.commentable_type == Opinio.model_name
|
104
|
+
if commentable.commentable_type == Opinio.model_name
|
105
|
+
errors.add :base, I18n.translate('opinio.cannot_be_comment_of_comment', :default => 'Cannot reply another comment\'s reply')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Opinio
|
2
|
+
module OpinioSubjectum
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def opinio_subjectum(*args)
|
10
|
+
options = args.extract_options!
|
11
|
+
|
12
|
+
has_many :comments,
|
13
|
+
:class_name => Opinio.model_name,
|
14
|
+
:as => :commentable,
|
15
|
+
:order => options.reverse_merge(:order => "created_at DESC")[:order],
|
16
|
+
:dependent => :destroy
|
17
|
+
|
18
|
+
|
19
|
+
send :include, Opinio::OpinioSubjectum::InstanceMethods
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module InstanceMethods
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract/schema_definitions'
|
2
|
+
|
3
|
+
module Opinio
|
4
|
+
module Orm
|
5
|
+
module ActiveRecord
|
6
|
+
module Schema
|
7
|
+
include Opinio::Schema
|
8
|
+
# Tell how to apply schema methods.
|
9
|
+
def apply_opinio_schema(name, type, options={})
|
10
|
+
column name, type.to_s.downcase.to_sym, options
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
ActiveRecord::ConnectionAdapters::Table.send :include, Opinio::Orm::ActiveRecord::Schema
|
18
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Opinio::Orm::ActiveRecord::Schema
|
19
|
+
|
data/lib/opinio/rails.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActionDispatch::Routing
|
2
|
+
class Mapper
|
3
|
+
def opinio(*args)
|
4
|
+
options = args.extract_options!.symbolize_keys
|
5
|
+
route_name = options[:path_name] || Opinio.model_name.pluralize.downcase
|
6
|
+
options[:controller] ||= 'opinio/comments'
|
7
|
+
|
8
|
+
get "#{ route_name }(/:page)" => "#{options[:controller].to_s}#index", :as => :comments
|
9
|
+
end
|
10
|
+
|
11
|
+
def opinio_model(*args)
|
12
|
+
options = args.extract_options!
|
13
|
+
options[:controller] ||= 'opinio/comments'
|
14
|
+
resources :comments, :controller => options[:controller] do
|
15
|
+
get 'reply', :on => :member if Opinio.accept_replies
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module Opinio
|
4
|
+
class Railtie < ::Rails::Railtie #:nodoc:
|
5
|
+
initializer 'opinio' do |app|
|
6
|
+
ActiveSupport.on_load(:active_record) do
|
7
|
+
require File.join(File.dirname(__FILE__), 'opinio_model')
|
8
|
+
require File.join(File.dirname(__FILE__), 'opinio_subjectum')
|
9
|
+
::ActiveRecord::Base.send :include, Opinio::OpinioModel
|
10
|
+
::ActiveRecord::Base.send :include, Opinio::OpinioSubjectum
|
11
|
+
end
|
12
|
+
ActiveSupport.on_load(:action_view) do
|
13
|
+
require File.join(File.dirname(__FILE__), 'controllers', 'helpers')
|
14
|
+
::ActionView::Base.send :include, Opinio::Controllers::Helpers
|
15
|
+
end
|
16
|
+
ActiveSupport.on_load(:action_controller) do
|
17
|
+
require File.join(File.dirname(__FILE__), 'controllers', 'extensions')
|
18
|
+
::ActionController::Base.send :include, Opinio::Controllers::Extensions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Schema
|
3
|
+
|
4
|
+
def opinio(options = {})
|
5
|
+
null = options[:null] || false
|
6
|
+
default = options.key?(:default) ? options[:default] : ("" if null == false)
|
7
|
+
|
8
|
+
apply_opinio_schema :owner_id, :integer, :null => false
|
9
|
+
apply_opinio_schema :commentable_id, :integer, :null => false
|
10
|
+
apply_opinio_schema :commentable_type, :string, :null => false
|
11
|
+
apply_opinio_schema :title, :string, :default => default, :null => null if options[:title]
|
12
|
+
apply_opinio_schema :body, :text, :null => false
|
13
|
+
end
|
14
|
+
|
15
|
+
# Overwrite with specific modification to create your own schema.
|
16
|
+
def apply_opinio_schema(name, type, options={})
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opinio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Luiz Felipe Garcia Pereira
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-09 00:00:00.000000000 -03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
description: Opinio is an engine used to add comments functionallity to rails 3 applications.
|
16
|
+
email:
|
17
|
+
- luiz.felipe.gp@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- app/controllers/opinio/comments_controller.rb
|
23
|
+
- app/views/opinio/comments/_comment.html.erb
|
24
|
+
- app/views/opinio/comments/_comments.html.erb
|
25
|
+
- app/views/opinio/comments/_new.html.erb
|
26
|
+
- app/views/opinio/comments/create.js.erb
|
27
|
+
- app/views/opinio/comments/destroy.js.erb
|
28
|
+
- app/views/opinio/comments/index.html.erb
|
29
|
+
- app/views/opinio/comments/reply.js.erb
|
30
|
+
- lib/generators/opinio/install/install_generator.rb
|
31
|
+
- lib/generators/opinio/install/templates/initializers/opinio.erb
|
32
|
+
- lib/generators/opinio/install/templates/migrations/create_model.rb
|
33
|
+
- lib/generators/opinio/install/templates/models/model.rb
|
34
|
+
- lib/generators/opinio/views/views_generator.rb
|
35
|
+
- lib/opinio/controllers/extensions.rb
|
36
|
+
- lib/opinio/controllers/helpers.rb
|
37
|
+
- lib/opinio/controllers/internal_helpers.rb
|
38
|
+
- lib/opinio/controllers/replies.rb
|
39
|
+
- lib/opinio/opinio_model.rb
|
40
|
+
- lib/opinio/opinio_subjectum.rb
|
41
|
+
- lib/opinio/orm/active_record.rb
|
42
|
+
- lib/opinio/rails/routes.rb
|
43
|
+
- lib/opinio/rails.rb
|
44
|
+
- lib/opinio/railtie.rb
|
45
|
+
- lib/opinio/schema.rb
|
46
|
+
- lib/opinio/version.rb
|
47
|
+
- lib/opinio.rb
|
48
|
+
- MIT-LICENSE
|
49
|
+
- Rakefile
|
50
|
+
- Gemfile
|
51
|
+
- README.rdoc
|
52
|
+
has_rdoc: true
|
53
|
+
homepage:
|
54
|
+
licenses: []
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.6.2
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: A rails 3 engine for comments.
|
77
|
+
test_files: []
|