opinio 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|