opinio-bootstrap 0.6.0.2
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 +31 -0
- data/MIT-LICENSE +20 -0
- data/README.md +197 -0
- data/Rakefile +28 -0
- data/app/controllers/opinio/comments_controller.rb +47 -0
- data/app/views/opinio/comments/_comment.html.erb +20 -0
- data/app/views/opinio/comments/_comments.html.erb +12 -0
- data/app/views/opinio/comments/_new.html.erb +19 -0
- data/app/views/opinio/comments/create.js.erb +16 -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 +6 -0
- data/config/locales/opinio.en.yml +16 -0
- data/lib/generators/opinio/install/install_generator.rb +38 -0
- data/lib/generators/opinio/install/templates/initializers/opinio.erb +28 -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 +27 -0
- data/lib/opinio.rb +66 -0
- data/lib/opinio/controllers/extensions.rb +39 -0
- data/lib/opinio/controllers/helpers.rb +22 -0
- data/lib/opinio/controllers/internal_helpers.rb +37 -0
- data/lib/opinio/controllers/replies.rb +23 -0
- data/lib/opinio/opinio_model.rb +77 -0
- data/lib/opinio/opinio_model/validations.rb +50 -0
- data/lib/opinio/opinio_subjectum.rb +24 -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/shared_examples.rb +89 -0
- data/lib/opinio/version.rb +5 -0
- metadata +145 -0
data/Gemfile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem "kaminari"
|
6
|
+
gem "rails", "~> 3.0.0"
|
7
|
+
gem "sqlite3"
|
8
|
+
gem "jquery-rails"
|
9
|
+
|
10
|
+
group :development do
|
11
|
+
platforms :mri_19 do
|
12
|
+
gem "debugger"
|
13
|
+
end
|
14
|
+
gem 'guard-rspec'
|
15
|
+
if RUBY_PLATFORM =~ /darwin/i
|
16
|
+
gem 'rb-fsevent'
|
17
|
+
gem 'growl'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
group :test do
|
22
|
+
gem "cucumber"
|
23
|
+
gem "cucumber-rails"
|
24
|
+
gem "capybara"
|
25
|
+
gem "launchy"
|
26
|
+
gem "database_cleaner"
|
27
|
+
gem "rspec-rails", :git => "https://github.com/rspec/rspec-rails.git", :tag => "v2.12.2"
|
28
|
+
end
|
29
|
+
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
|
30
|
+
# gem 'ruby-debug'
|
31
|
+
# 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.md
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# Opinio-Bootstrap #
|
2
|
+
|
3
|
+
## Description ##
|
4
|
+
|
5
|
+
This is a fork of Luiz Pereira's great [Opinio](https://github.com/Draiken/opinio) gem for Rails 3+.
|
6
|
+
|
7
|
+
It intends to simply utilize [Twitter Bootstrap](http://twitter.github.com/bootstrap/) styling in views out-of-the-box.
|
8
|
+
|
9
|
+
In particular, it utilizes the media-object component.
|
10
|
+
|
11
|
+
Currently it requires an image_url(:thumb) method (the default for [Carrierwave](https://github.com/jnicklas/carrierwave)) for your User object; If you are set up with Bootstrap and are storing an image on the User, styling will automatically include the User's avatar along with a link to the user, along with the comment and associated links.
|
12
|
+
|
13
|
+
So you need a valid call to
|
14
|
+
|
15
|
+
@user.image_url(:thumb).to_s
|
16
|
+
|
17
|
+
for the avatar image (media object).
|
18
|
+
|
19
|
+
To do: make dynamic the method by which User's image is called; provide a default stock placeholder image for those not utilizing an image mounting system for their User object (e.g. Carrierwave/Paperclip).
|
20
|
+
|
21
|
+
Make sure Bootstrap is in your Rails *Gemfile*:
|
22
|
+
|
23
|
+
gem "bootstrap-sass", ">= 2.2.2.0"
|
24
|
+
|
25
|
+
The remainder of this page is [Opinio](https://github.com/Draiken/opinio)'s original README.
|
26
|
+
|
27
|
+
## Original ##
|
28
|
+
|
29
|
+
**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)
|
30
|
+
|
31
|
+
## Description ##
|
32
|
+
|
33
|
+
Opinio is an engine used to add comments behaviour to your application.
|
34
|
+
The engine is designed to work only with **Rails 3**
|
35
|
+
|
36
|
+
## Intallation ##
|
37
|
+
|
38
|
+
Simply add the following line to your *Gemfile*:
|
39
|
+
|
40
|
+
gem "opinio"
|
41
|
+
|
42
|
+
and run:
|
43
|
+
|
44
|
+
bundle
|
45
|
+
|
46
|
+
## Usage ##
|
47
|
+
|
48
|
+
Opinio provides generators to facilitate it's usage.
|
49
|
+
The most common way to quickly get Opinio working is:
|
50
|
+
|
51
|
+
rails g opinio:install comment
|
52
|
+
|
53
|
+
This will generate the `Comment` model, migration and also generate the opinio initializer for customization of the engine.
|
54
|
+
A `opinio_model` will be added on the `routes.rb`. This method adds the default urls for the model that will act as the comment
|
55
|
+
in your app.
|
56
|
+
|
57
|
+
In order to add the comments functionality to a model, you use the `opinio_subjectum` method
|
58
|
+
|
59
|
+
class Post < ActiveRecord::Base
|
60
|
+
opinio_subjectum
|
61
|
+
end
|
62
|
+
|
63
|
+
On the `routes.rb` you should simply add an `opinio` for your commentable resource
|
64
|
+
|
65
|
+
resources :posts do
|
66
|
+
opinio
|
67
|
+
end
|
68
|
+
|
69
|
+
To render the comments in your views, there is a helper to display the resource's comments easily:
|
70
|
+
|
71
|
+
<%= comments_for @post %>
|
72
|
+
|
73
|
+
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:
|
74
|
+
|
75
|
+
<%= render_comments @post %>
|
76
|
+
<%= render_comments_form @post %>
|
77
|
+
|
78
|
+
If you need to render the comments with a specific page or limit
|
79
|
+
you can use Kaminari's configurations like `paginates_per 10` on your comment model
|
80
|
+
or you can customize it for specific views on the helpers
|
81
|
+
|
82
|
+
<%= render_comments @post, :page => params[:page], :limit => 5 %>
|
83
|
+
|
84
|
+
This options can also be used on the `comments_for` helper.
|
85
|
+
|
86
|
+
## Customization ##
|
87
|
+
|
88
|
+
### Views ###
|
89
|
+
|
90
|
+
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:
|
91
|
+
|
92
|
+
rails g opinio:views
|
93
|
+
|
94
|
+
And you can customize all the views used by the engine.
|
95
|
+
|
96
|
+
### Behaviour ###
|
97
|
+
|
98
|
+
#### Opinio Model ####
|
99
|
+
|
100
|
+
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.
|
101
|
+
|
102
|
+
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.
|
103
|
+
|
104
|
+
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`.
|
105
|
+
|
106
|
+
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.
|
107
|
+
|
108
|
+
Remember that if you use titles, you need to add that to your comments table, since the generator doesn't add it by default.
|
109
|
+
|
110
|
+
#### Opinio Subjectum ####
|
111
|
+
|
112
|
+
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.
|
113
|
+
|
114
|
+
The default options are these:
|
115
|
+
|
116
|
+
has_many :comments,
|
117
|
+
:class_name => Opinio.model_name,
|
118
|
+
:as => :commentable,
|
119
|
+
:order => "created_at #{Opinio.sort_order}"),
|
120
|
+
:dependent => :destroy
|
121
|
+
|
122
|
+
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:
|
123
|
+
|
124
|
+
opinio_subjectum :conditions => ["approved = ?", true]
|
125
|
+
|
126
|
+
Remember you can override any of these options (except `as`) by passing them to the `opinio_subjectum` method.
|
127
|
+
|
128
|
+
#### Pretty Urls ####
|
129
|
+
|
130
|
+
Often times you will want the engine to show the index of comments for a specific item
|
131
|
+
without having to pass the `:commentable_type` or `:commentable_id` parameters.
|
132
|
+
|
133
|
+
In order to do that, opinio provides a method to `ActionController::Base`:
|
134
|
+
|
135
|
+
opinio_identifier do |params|
|
136
|
+
next Review.find(params[:review_id]) if params[:review_id]
|
137
|
+
next Product.find(params[:product_id]) if params[:product_id]
|
138
|
+
end
|
139
|
+
|
140
|
+
Note: you use next instead of return because it is a proc that will be executed later on, and you cannot return on procs
|
141
|
+
|
142
|
+
Basically on this method you receive the `params` variable and you tell the engine, who owns
|
143
|
+
the comments from that page.
|
144
|
+
This allows you to use routes like:
|
145
|
+
|
146
|
+
/products/1/comments
|
147
|
+
/products/1/reviews/1/comments
|
148
|
+
|
149
|
+
Without passing those 2 parameters.
|
150
|
+
I suggest you put this method on the `ApplicationController`
|
151
|
+
|
152
|
+
#### Customize destroy conditions ####
|
153
|
+
|
154
|
+
By default, noone can destroy a comment in the engine. You have to tell the engine who can do it.
|
155
|
+
To setup a custom destroy condition use the methods provided by opinio
|
156
|
+
in our controllers. For instance, if our opinio model is called 'comment'
|
157
|
+
it could be written like this:
|
158
|
+
|
159
|
+
comment_destroy_conditions do |comment|
|
160
|
+
comment.owner == current_user
|
161
|
+
end
|
162
|
+
|
163
|
+
This would make users only be able to remove their own comments.
|
164
|
+
Another example would be using the `CanCan`:
|
165
|
+
|
166
|
+
comment_destroy_conditions do |comment|
|
167
|
+
authorize :destroy, comment
|
168
|
+
end
|
169
|
+
|
170
|
+
You get the picture, you're inside your controller's methods on that block
|
171
|
+
so you can call anything your normal controllers call on actions.
|
172
|
+
|
173
|
+
### Testing ###
|
174
|
+
|
175
|
+
Opinio provides a few shared examples for testing of your model with rspec
|
176
|
+
On your opinio model test case you can require opinio's shared examples and use them
|
177
|
+
|
178
|
+
require 'opinio/shared_examples'
|
179
|
+
|
180
|
+
describe Comment do
|
181
|
+
it_should_behave_like :opinio
|
182
|
+
end
|
183
|
+
|
184
|
+
describe Post do
|
185
|
+
it_should_behave_like :opinio_subjectum
|
186
|
+
end
|
187
|
+
|
188
|
+
## Contribution ##
|
189
|
+
|
190
|
+
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.
|
191
|
+
For issues please use the github [issues tracker](https://github.com/Draiken/opinio/issues)
|
192
|
+
|
193
|
+
### TODO ###
|
194
|
+
|
195
|
+
* Refactor the `comments_for` helper
|
196
|
+
* Extract documentation to wiki
|
197
|
+
* Add mongoid support
|
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 'rdoc/task'
|
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,47 @@
|
|
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 = send(Opinio.current_user_method)
|
12
|
+
if @comment.save
|
13
|
+
flash_area = :notice
|
14
|
+
message = t('opinio.messages.comment_sent')
|
15
|
+
else
|
16
|
+
flash_area = :error
|
17
|
+
message = t('opinio.messages.comment_sending_error')
|
18
|
+
end
|
19
|
+
|
20
|
+
respond_to do |format|
|
21
|
+
format.js
|
22
|
+
format.html do
|
23
|
+
set_flash(flash_area, message)
|
24
|
+
redirect_to(opinio_after_create_path(resource))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def destroy
|
30
|
+
@comment = Opinio.model_name.constantize.find(params[:id])
|
31
|
+
|
32
|
+
if can_destroy_opinio?(@comment)
|
33
|
+
@comment.destroy
|
34
|
+
set_flash(:notice, t('opinio.messages.comment_destroyed'))
|
35
|
+
else
|
36
|
+
#flash[:error] = I18n.translate('opinio.comment.not_permitted', :default => "Not permitted")
|
37
|
+
logger.warn "user #{send(Opinio.current_user_method)} tried to remove a comment from another user #{@comment.owner.id}"
|
38
|
+
render :text => "unauthorized", :status => 401 and return
|
39
|
+
end
|
40
|
+
|
41
|
+
respond_to do |format|
|
42
|
+
format.js
|
43
|
+
format.html { redirect_to( opinio_after_destroy_path(@comment) ) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<% reply = defined?(reply) ? reply : false %>
|
2
|
+
<div id="comment_<%= comment.id %>" class="media">
|
3
|
+
<a class="pull-left" href="<%= user_path(comment.owner) %>">
|
4
|
+
<img class="media-object" src="<%= comment.owner.image_url(:thumb).to_s %>" />
|
5
|
+
<span><%= comment.owner.name.titlecase %></span>
|
6
|
+
</a>
|
7
|
+
<div class="media-body">
|
8
|
+
<%= simple_format(comment.body) %>
|
9
|
+
<% if comment.owner == send(Opinio.current_user_method) %>
|
10
|
+
<%= link_to t('opinio.actions.delete'), comment_path(comment), :method => :delete, :remote => true %>
|
11
|
+
<% end %>
|
12
|
+
<%# this enables only 1 level of replies %>
|
13
|
+
<% if Opinio.accept_replies && !reply && !(comment.owner == current_user) %>
|
14
|
+
<span><%= link_to t('opinio.actions.reply'), reply_comment_path(comment), :remote => true %></span>
|
15
|
+
<% end %>
|
16
|
+
<div id="comment_<%= comment.id %>_replies" class="replies media">
|
17
|
+
<%= render :partial => "opinio/comments/comment", :collection => comment.comments, :locals => {:reply => true} %>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div>
|
2
|
+
<%= paginate comments %>
|
3
|
+
</div>
|
4
|
+
<% unless comments.empty? %>
|
5
|
+
<%= render :partial => 'opinio/comments/comment', :collection => comments %>
|
6
|
+
<% else %>
|
7
|
+
<h3><%= t('opinio.messages.no_comments_found') %></h3>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<div>
|
11
|
+
<%= paginate comments %>
|
12
|
+
</div>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<div id="new_comment">
|
2
|
+
<% if send(Opinio.current_user_method) %>
|
3
|
+
<h3 class="addcomment"><%= t('opinio.messages.add_comment') %></h3>
|
4
|
+
<%= form_for Comment.new, :remote => false do |f| %>
|
5
|
+
<p>
|
6
|
+
<%= f.text_area :body, :placeholder => "Enter comment...", rows:"10" %>
|
7
|
+
</p>
|
8
|
+
<%= hidden_field_tag :commentable_id, commentable.id %>
|
9
|
+
<%= hidden_field_tag :commentable_type, commentable.class.base_class.name.to_s %>
|
10
|
+
<%= hidden_field_tag :original_controller, params[:controller] %>
|
11
|
+
<%= hidden_field_tag :original_id, params[:id] %>
|
12
|
+
<%= f.submit t('opinio.actions.add') %>
|
13
|
+
<% end %>
|
14
|
+
<% else %>
|
15
|
+
<p>
|
16
|
+
<%= t('opinio.messages.must_be_logged_in_to_comment') %>
|
17
|
+
</p>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
$('#no_comments').hide();
|
2
|
+
<% if @comment.valid? %>
|
3
|
+
<% if @reply %>
|
4
|
+
if($('#comment_<%= @comment.commentable_id %> ul').length == 0)
|
5
|
+
$('#comment_<%= @comment.commentable_id %>').append('<ul id="comment_<%= @comment.commentable_id %>_replies" class="replies"></ul>');
|
6
|
+
$('#comment_<%= @comment.commentable_id %>_replies').append("<%= escape_javascript( render @comment, :locals => {:reply => @reply} ) %>");
|
7
|
+
$('#commentable_id').val('<%= @comment.commentable.commentable_id %>');
|
8
|
+
$('#commentable_type').val('<%= @comment.commentable.commentable_type %>');
|
9
|
+
<% else %>
|
10
|
+
$('#comments').<%= Opinio.sort_order == 'ASC' ? 'append' : 'prepend'%>("<%= escape_javascript( render @comment, :locals => {:reply => @reply} ) %>");
|
11
|
+
<% end %>
|
12
|
+
$('textarea#comment_body').val('');
|
13
|
+
<% else %>
|
14
|
+
$('#comments').prepend("<%= escape_javascript(flash[:notice]) %>");
|
15
|
+
$('#comments').prepend("<%= escape_javascript(flash[:error]) %>");
|
16
|
+
<% end %>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<% @comment = Comment.find(@commentable_id) %>
|
2
|
+
$("#commentable_id").val('<%= @commentable_id %>');
|
3
|
+
$("#commentable_type").val('<%= @commentable_type %>');
|
4
|
+
$("#new_comment textarea").val('');
|
5
|
+
$("#new_comment h3.addcomment").text('Replying to <%= @comment.owner.name.titlecase %>');
|
6
|
+
$("#new_comment textarea").focus();
|
@@ -0,0 +1,16 @@
|
|
1
|
+
en:
|
2
|
+
opinio:
|
3
|
+
actions:
|
4
|
+
delete: 'Delete'
|
5
|
+
reply: 'Reply'
|
6
|
+
add: 'Add comment'
|
7
|
+
messages:
|
8
|
+
no_comments_found: 'No comments found'
|
9
|
+
must_be_logged_in_to_comment: 'Must be logged in to comment.'
|
10
|
+
add_comment: 'Add comment'
|
11
|
+
comments: 'Comments'
|
12
|
+
comment_sent: 'Comment sent successfully.'
|
13
|
+
comment_sending_error: 'Error while sending the comment.'
|
14
|
+
comment_destroyed: 'Comment removed successfully.'
|
15
|
+
comment_interval: 'You must wait %{time} seconds to comment again.'
|
16
|
+
cannot_be_comment_of_comment: "Cannot reply another comment's reply"
|
@@ -0,0 +1,38 @@
|
|
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 add_dependency_gem
|
26
|
+
gem "kaminari"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.next_migration_number(dirname)
|
30
|
+
if ActiveRecord::Base.timestamped_migrations
|
31
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
32
|
+
else
|
33
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Opinio Configuration
|
2
|
+
|
3
|
+
Opinio.setup do |config|
|
4
|
+
|
5
|
+
# Use this to change the class that calls +opinio+ method
|
6
|
+
config.model_name = "<%= class_name %>"
|
7
|
+
|
8
|
+
# This is the owner class of the comment (opinio model)
|
9
|
+
# config.owner_class_name = "User"
|
10
|
+
|
11
|
+
# Change this if you do not want to allow replies on your comments
|
12
|
+
# config.accept_replies = true
|
13
|
+
|
14
|
+
# Here you can change the method called to check who is the current user
|
15
|
+
# config.current_user_method = :current_user
|
16
|
+
|
17
|
+
# Strip html tags on save comment
|
18
|
+
config.strip_html_tags_on_save = true
|
19
|
+
|
20
|
+
# Comments sort order by created_at (DESC or ASC)
|
21
|
+
# Note: you can override that easily within each opinio subjectum
|
22
|
+
config.sort_order = 'DESC'
|
23
|
+
|
24
|
+
# Wether or not the default opinio controller should set the flash
|
25
|
+
# when creating/removing comments
|
26
|
+
config.set_flash = true
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Generators
|
3
|
+
class ViewsGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
source_root File.expand_path('../../../../../app/views/opinio/comments', __FILE__)
|
6
|
+
|
7
|
+
class_option :haml, :desc => 'Generate HAML views instead of ERB.', :type => :boolean
|
8
|
+
|
9
|
+
def copy_views
|
10
|
+
html_names = ["_comment", "_comments", "_new", "index"]
|
11
|
+
js_names = ["create", "destroy", "reply"]
|
12
|
+
html_names.each do |name|
|
13
|
+
copy_file "#{name}.html.#{view_language}", "app/views/opinio/comments/#{name}.html.#{view_language}"
|
14
|
+
end
|
15
|
+
js_names.each do |name|
|
16
|
+
copy_file "#{name}.js.erb", "app/views/opinio/comments/#{name}.js.erb"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def view_language
|
21
|
+
options.haml? ? 'haml' : 'erb'
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/opinio.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Opinio
|
2
|
+
require 'opinio/schema'
|
3
|
+
|
4
|
+
module Controllers
|
5
|
+
require 'opinio/controllers/helpers'
|
6
|
+
require 'opinio/controllers/internal_helpers'
|
7
|
+
require 'opinio/controllers/replies'
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'opinio/railtie'
|
11
|
+
require 'opinio/rails'
|
12
|
+
require 'opinio/orm/active_record'
|
13
|
+
|
14
|
+
mattr_accessor :model_name
|
15
|
+
@@model_name = "Comment"
|
16
|
+
|
17
|
+
mattr_accessor :owner_class_name
|
18
|
+
@@owner_class_name = "User"
|
19
|
+
|
20
|
+
mattr_accessor :use_title
|
21
|
+
@@use_title = false
|
22
|
+
|
23
|
+
mattr_accessor :accept_replies
|
24
|
+
@@accept_replies = false
|
25
|
+
|
26
|
+
mattr_accessor :custom_identifiers
|
27
|
+
@@custom_identifiers = Array.new
|
28
|
+
|
29
|
+
mattr_accessor :interval_between_comments
|
30
|
+
@@interval_between_comments = false
|
31
|
+
|
32
|
+
mattr_accessor :destroy_conditions
|
33
|
+
@@destroy_conditions = Proc.new { false }
|
34
|
+
|
35
|
+
mattr_accessor :current_user_method
|
36
|
+
@@current_user_method = :current_user
|
37
|
+
|
38
|
+
mattr_accessor :strip_html_tags_on_save
|
39
|
+
@@strip_html_tags_on_save = true
|
40
|
+
|
41
|
+
mattr_accessor :sort_order
|
42
|
+
@@sort_order = 'DESC'
|
43
|
+
|
44
|
+
mattr_accessor :set_flash
|
45
|
+
@@set_flash = true
|
46
|
+
|
47
|
+
def self.setup
|
48
|
+
yield self
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.opinio_identifier(block)
|
52
|
+
@@custom_identifiers << block
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.set_destroy_conditions(&block)
|
56
|
+
@@destroy_conditions = block
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.check_custom_identifiers(params)
|
60
|
+
self.custom_identifiers.each do |identifier|
|
61
|
+
identified = identifier.call(params)
|
62
|
+
return identified unless identified.nil?
|
63
|
+
end
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Opinio
|
2
|
+
module Controllers
|
3
|
+
module Extensions
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.send :include, InstanceMethods
|
8
|
+
|
9
|
+
base.class_eval do
|
10
|
+
(class << self; self; end).instance_eval do
|
11
|
+
define_method "#{Opinio.model_name.underscore}_destroy_conditions" do |&block|
|
12
|
+
Opinio.set_destroy_conditions( &block )
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def opinio_identifier(&block)
|
20
|
+
Opinio.opinio_identifier(block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
def can_destroy_opinio?(opinio)
|
26
|
+
self.instance_exec(opinio, &Opinio.destroy_conditions)
|
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
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
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
|
+
page = options.delete(:page) || 1
|
13
|
+
render( :partial => "opinio/comments/comments", :locals => {:comments => object.comments.page(page).limit(limit), :commentable => object, :options => options} )
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_comments_form(object, options = {})
|
17
|
+
render( :partial => "opinio/comments/new", :locals => {:commentable => object, :options => options} )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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
|
+
|
32
|
+
def set_flash(name, message)
|
33
|
+
flash[name] = message if Opinio.set_flash
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
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,77 @@
|
|
1
|
+
require 'opinio/opinio_model/validations'
|
2
|
+
|
3
|
+
module Opinio
|
4
|
+
module OpinioModel
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
# Adds the Opinio functionallity to the model
|
13
|
+
# You can pass a hash of options to customize the Opinio model
|
14
|
+
def opinio(*args)
|
15
|
+
return if self.included_modules.include?(Opinio::OpinioModel::Validations)
|
16
|
+
options = args.extract_options!
|
17
|
+
|
18
|
+
if Opinio.use_title
|
19
|
+
attr_accessible :title
|
20
|
+
end
|
21
|
+
attr_accessible :body
|
22
|
+
|
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)
|
25
|
+
|
26
|
+
scope :owned_by, lambda {|owner| where('owner_id = ?', owner.id) }
|
27
|
+
|
28
|
+
send :include, Opinio::OpinioModel::Validations
|
29
|
+
|
30
|
+
if Opinio.accept_replies
|
31
|
+
send :include, RepliesSupport
|
32
|
+
end
|
33
|
+
|
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
|
44
|
+
send :include, ActionView::Helpers::SanitizeHelper
|
45
|
+
before_save :strip_html_tags
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def strip_html_tags
|
52
|
+
self.body = strip_tags(self.body)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module RepliesSupport
|
57
|
+
def self.included(base)
|
58
|
+
base.class_eval do
|
59
|
+
validate :cannot_be_comment_of_a_comments_comment
|
60
|
+
opinio_subjectum :order => 'created_at ASC'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Validates that you cannot comment on a comment's comment
|
67
|
+
def cannot_be_comment_of_a_comments_comment
|
68
|
+
if new_record? && self.commentable_type == Opinio.model_name
|
69
|
+
if commentable.commentable_type == Opinio.model_name
|
70
|
+
errors.add :base, I18n.t('opinio.messages.cannot_be_comment_of_comment')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
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
|
@@ -0,0 +1,24 @@
|
|
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
|
+
options.delete(:as)
|
12
|
+
|
13
|
+
default_options = { :class_name => Opinio.model_name,
|
14
|
+
:as => :commentable,
|
15
|
+
:order => "created_at #{Opinio.sort_order}",
|
16
|
+
:dependent => :destroy }
|
17
|
+
|
18
|
+
has_many :comments, default_options.merge(options)
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
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, options 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
|
@@ -0,0 +1,89 @@
|
|
1
|
+
shared_examples_for :opinio do
|
2
|
+
|
3
|
+
let(:comment) { Comment.new }
|
4
|
+
let(:owner) { User.create }
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
@post = Post.new(:title => "My first post", :body => "Damn I really suck at writing")
|
8
|
+
@post.save
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have the correct attributes" do
|
12
|
+
should respond_to(:owner)
|
13
|
+
should respond_to(:body)
|
14
|
+
should respond_to(:commentable)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
it "should not allow comments of comments" do
|
19
|
+
Comment.class_eval do
|
20
|
+
include Opinio::OpinioModel::RepliesSupport
|
21
|
+
end
|
22
|
+
|
23
|
+
c = Comment.new(:body => "The Comment !")
|
24
|
+
c.commentable = @post
|
25
|
+
c.owner = owner
|
26
|
+
c.save.should == true
|
27
|
+
|
28
|
+
c2 = Comment.new(:body => "The Comment !")
|
29
|
+
c2.owner = owner
|
30
|
+
c2.commentable = c
|
31
|
+
c2.save.should == true
|
32
|
+
|
33
|
+
c3 = c2.dup
|
34
|
+
c3.commentable = c2
|
35
|
+
c3.save.should == false
|
36
|
+
|
37
|
+
c3.errors[:base].count.should == 1
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should validate presence of body and commentable" do
|
41
|
+
comment.should be_invalid
|
42
|
+
comment.errors[:body].should be_present
|
43
|
+
comment.errors[:commentable].should be_present
|
44
|
+
end
|
45
|
+
|
46
|
+
it "and it should insist on having an owner" do
|
47
|
+
c = Comment.new(:body => "The Comment !")
|
48
|
+
c.commentable = @post
|
49
|
+
c.save.should == false
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when strip_html_tags_on_save is true" do
|
53
|
+
it "should strip html tags" do
|
54
|
+
comment = create_valid_comment('<h1>Chuck will save us!</h1>')
|
55
|
+
comment.body.should == 'Chuck will save us!'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when strip_html_tags_on_save is false" do
|
60
|
+
|
61
|
+
# we have to create a different class
|
62
|
+
# because opinio adds the strip tags callbacks
|
63
|
+
# only once when opinio is called on the class
|
64
|
+
class NoSanitizerComment < ActiveRecord::Base
|
65
|
+
self.table_name = :comments
|
66
|
+
end
|
67
|
+
|
68
|
+
before do
|
69
|
+
Opinio.stub(:strip_html_tags_on_save).and_return(false)
|
70
|
+
NoSanitizerComment.class_eval do
|
71
|
+
opinio
|
72
|
+
end
|
73
|
+
end
|
74
|
+
it "should not strip html tags" do
|
75
|
+
comment = create_valid_comment('<h1>Chuck will save us!</h1>', NoSanitizerComment)
|
76
|
+
comment.body.should == '<h1>Chuck will save us!</h1>'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
shared_examples_for :opinio_subjectum do
|
84
|
+
|
85
|
+
it "and should add opinio_subjectum functionallity" do
|
86
|
+
should respond_to(:comments)
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opinio-bootstrap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Luiz Felipe Garcia Pereira
|
9
|
+
- Richard Carey
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-02-10 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '3'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: kaminari
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: jquery-rails
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: bootstrap-sass
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 2.2.2.0
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 2.2.2.0
|
79
|
+
description: Opinio is an engine used to add comments functionallity to rails 3 applications;
|
80
|
+
this version is adapted to Twitter Bootstrap.
|
81
|
+
email:
|
82
|
+
- luiz.felipe.gp@gmail.com
|
83
|
+
- rc@rcdmcg.com
|
84
|
+
executables: []
|
85
|
+
extensions: []
|
86
|
+
extra_rdoc_files: []
|
87
|
+
files:
|
88
|
+
- app/controllers/opinio/comments_controller.rb
|
89
|
+
- app/views/opinio/comments/_comment.html.erb
|
90
|
+
- app/views/opinio/comments/_comments.html.erb
|
91
|
+
- app/views/opinio/comments/_new.html.erb
|
92
|
+
- app/views/opinio/comments/create.js.erb
|
93
|
+
- app/views/opinio/comments/destroy.js.erb
|
94
|
+
- app/views/opinio/comments/index.html.erb
|
95
|
+
- app/views/opinio/comments/reply.js.erb
|
96
|
+
- lib/generators/opinio/install/install_generator.rb
|
97
|
+
- lib/generators/opinio/install/templates/initializers/opinio.erb
|
98
|
+
- lib/generators/opinio/install/templates/migrations/create_model.rb
|
99
|
+
- lib/generators/opinio/install/templates/models/model.rb
|
100
|
+
- lib/generators/opinio/views/views_generator.rb
|
101
|
+
- lib/opinio/controllers/extensions.rb
|
102
|
+
- lib/opinio/controllers/helpers.rb
|
103
|
+
- lib/opinio/controllers/internal_helpers.rb
|
104
|
+
- lib/opinio/controllers/replies.rb
|
105
|
+
- lib/opinio/opinio_model/validations.rb
|
106
|
+
- lib/opinio/opinio_model.rb
|
107
|
+
- lib/opinio/opinio_subjectum.rb
|
108
|
+
- lib/opinio/orm/active_record.rb
|
109
|
+
- lib/opinio/rails/routes.rb
|
110
|
+
- lib/opinio/rails.rb
|
111
|
+
- lib/opinio/railtie.rb
|
112
|
+
- lib/opinio/schema.rb
|
113
|
+
- lib/opinio/shared_examples.rb
|
114
|
+
- lib/opinio/version.rb
|
115
|
+
- lib/opinio.rb
|
116
|
+
- config/locales/opinio.en.yml
|
117
|
+
- MIT-LICENSE
|
118
|
+
- Rakefile
|
119
|
+
- Gemfile
|
120
|
+
- README.md
|
121
|
+
homepage: https://github.com/rceee/opinio-bootstrap
|
122
|
+
licenses: []
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ! '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 1.8.24
|
142
|
+
signing_key:
|
143
|
+
specification_version: 3
|
144
|
+
summary: A rails 3 engine for comments, with Twitter Bootstrap styling.
|
145
|
+
test_files: []
|