acts_as_reviewable 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +13 -0
- data/MIT-LICENSE +20 -0
- data/README.md +321 -0
- data/Rakefile +25 -0
- data/lib/acts_as_reviewable.rb +2 -0
- data/lib/generators/review/USAGE +6 -0
- data/lib/generators/review/review_generator.rb +19 -0
- data/lib/generators/review/templates/create_reviews.rb +21 -0
- data/lib/generators/review/templates/review.rb +15 -0
- data/lib/review_methods.rb +42 -0
- data/lib/reviewable_methods.rb +71 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1a1092dcf9cab7737bf24efc3ffa2305648b5553
|
4
|
+
data.tar.gz: 0c2d95915e84ecd557a57082e3ddc2d9440a4e96
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 63757e0b3829e8ec3c2a0db917d8609a45ddcd72fd4c9758f743fa9ded8f76f6d1d50adeec36f5a416b3fb9a3c86819a3a2b79c891cf436593ef35fe4150a968
|
7
|
+
data.tar.gz: 7fb55d75509c2055769d653eb647455962be041657027c68c35145f7133aaf13bd646f98441c79e905a48a00b46a53198fd9fb4c9a3df7dbb907d4d2ced380b1
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "rails", "3.0.5"
|
4
|
+
gem "capybara", ">= 0.4.0"
|
5
|
+
gem "sqlite3"
|
6
|
+
|
7
|
+
gem "rspec-rails", ">= 2.0.0.beta"
|
8
|
+
gem "genspec"
|
9
|
+
|
10
|
+
|
11
|
+
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
|
12
|
+
# gem 'ruby-debug'
|
13
|
+
# 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,321 @@
|
|
1
|
+
# ActsAsReviewable
|
2
|
+
|
3
|
+
Reviews for any AR model with multi-dimensional ratings, review commentary, and info-graphics.
|
4
|
+
|
5
|
+
## ActsAsReviewable - concept v0.0.1.
|
6
|
+
|
7
|
+
_Rails: Make an ActiveRecord resource rateable/reviewable (rating + comment) across multiple dimensions with infographics._
|
8
|
+
|
9
|
+
## Why another rating/review-plugin?
|
10
|
+
|
11
|
+
Existing plugins rate on one dimension and provide basic analytics and no charting.
|
12
|
+
|
13
|
+
* Don't assume that your rater/reviewer model is *User*. Use polymorphic associations, so your reviewer can be...*anymodel*.
|
14
|
+
* Don't make assumptions about the rating scale, how it should be divided, or rounding precision for stats.
|
15
|
+
The 1-5 scale is 80% of the cases, but there's no real reason or overhead to support any scale. To sum it up: Scale
|
16
|
+
can consist negative and/or positive range or explicit integer/float values...and you won't even notice the
|
17
|
+
difference on the outside. See the examples! =)
|
18
|
+
* Possible to submit additional custom attributes while rating, such as a *title* and *body* to make up a "review" instead of just a "rating". Feel free.
|
19
|
+
* Finders implemented using scopes, i.e.. less code smell.
|
20
|
+
* Information graphics provided as an optional extension to the plugin. Engine for charting would be useful, even if just for admins.
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
*Gem:*
|
25
|
+
|
26
|
+
`gem install acts_as_reviewable`
|
27
|
+
|
28
|
+
for rails 3, in your Gemfile:
|
29
|
+
|
30
|
+
`gem 'acts_as_reviewable'`
|
31
|
+
|
32
|
+
# Usage
|
33
|
+
|
34
|
+
## 1. Generate migration:
|
35
|
+
|
36
|
+
`$ rails generate acts_as_reviewable_migration`
|
37
|
+
|
38
|
+
Generates *db/migrations/{timestamp}_acts_as_reviewable_migration* with
|
39
|
+
|
40
|
+
|
41
|
+
<pre>
|
42
|
+
class ActsAsReviewableMigration < ActiveRecord::Migration
|
43
|
+
def self.up
|
44
|
+
create_table :reviews do |t|
|
45
|
+
t.references :reviewable, :polymorphic => true
|
46
|
+
|
47
|
+
t.references :reviewer, :polymorphic => true
|
48
|
+
|
49
|
+
t.float :rating
|
50
|
+
t.text :comment
|
51
|
+
|
52
|
+
#
|
53
|
+
# Custom fields go here...
|
54
|
+
#
|
55
|
+
# t.string :title
|
56
|
+
# t.string :intention
|
57
|
+
# ...
|
58
|
+
#
|
59
|
+
|
60
|
+
t.timestamps
|
61
|
+
end
|
62
|
+
|
63
|
+
add_index :reviews, :reviewer_id
|
64
|
+
add_index :reviews, :reviewer_type
|
65
|
+
add_index :reviews, [:reviewer_id, :reviewer_type]
|
66
|
+
add_index :reviews, [:reviewable_id, :reviewable_type]
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.down
|
70
|
+
drop_table :reviews
|
71
|
+
end
|
72
|
+
end
|
73
|
+
</pre>
|
74
|
+
|
75
|
+
## 2. Make your model reviewable:
|
76
|
+
<pre>
|
77
|
+
class Post < ActiveRecord::Base
|
78
|
+
acts_as_reviewable :scale => 0..5
|
79
|
+
end
|
80
|
+
</pre>
|
81
|
+
|
82
|
+
or, with explicit reviewer (or reviewers):
|
83
|
+
|
84
|
+
<pre>
|
85
|
+
class Book < ActiveRecord::Base
|
86
|
+
# Setup associations for the reviewer class(es) automatically, and specify an explicit scale instead.
|
87
|
+
acts_as_reviewable :by => [:users, :authors], :scale => 0..5
|
88
|
+
end
|
89
|
+
</pre>
|
90
|
+
|
91
|
+
## 3. API - a stable public api is scheduled for release 1.0.0 (plausibly June 2011)
|
92
|
+
|
93
|
+
Examples:
|
94
|
+
|
95
|
+
<pre>
|
96
|
+
Review.destroy_all # just in case...
|
97
|
+
@post = Post.first
|
98
|
+
@user = User.first
|
99
|
+
|
100
|
+
@post.review!(:by => @user, :rating => 2) # new reviewer (type: object) => create
|
101
|
+
@post.review!(:by => @user, :rating => 5) # same reviewer (type: object) => update
|
102
|
+
|
103
|
+
@post.total_reviews # => 1
|
104
|
+
@post.average_rating # => 5.0
|
105
|
+
|
106
|
+
@post.total_reviews # => 2
|
107
|
+
@post.average_rating # => 3.5
|
108
|
+
|
109
|
+
@post.review!(:by => @user, :rating => nil, :body => "Lorem ipsum...") # same reviewer (type: IP) => update
|
110
|
+
|
111
|
+
@post.total_reviews # => 2
|
112
|
+
@post.average_rating # => 2.0, i.e. don't count nil (a.k.a. "no opinion")
|
113
|
+
|
114
|
+
@post.unreview!(:by => @user) # delete existing review (type: User) => destroy
|
115
|
+
|
116
|
+
@post.total_reviews # => 1
|
117
|
+
@post.average_rating # => 2.0
|
118
|
+
|
119
|
+
@post.reviews # => reviews on @post
|
120
|
+
@post.reviewers # => reviewers that reviewed @post
|
121
|
+
@user.reviews # => reviews by @user
|
122
|
+
@user.reviewables # => reviewable objects that got reviewed by @user
|
123
|
+
|
124
|
+
# TODO: A few more samples...
|
125
|
+
|
126
|
+
# etc...
|
127
|
+
</pre>
|
128
|
+
|
129
|
+
# Mixin Arguments
|
130
|
+
|
131
|
+
The *acts_as_reviewable* mixin takes the following hash arguments for customization:
|
132
|
+
|
133
|
+
*Basic*
|
134
|
+
|
135
|
+
* *:by* - the reviewer model(s), e.g. User, Account, etc. (accepts either symbol or class, i.e. *User* <=> *:user* <=> *:users*, or an array of such if there are more than one reviewer model). The reviewer model will be setup for you. Note: Polymorhic, so it accepts any model. Default: *nil*.
|
136
|
+
* *:scale* / *:range* / *:values* - range, or array, of valid rating values. Default: *1..5*. Note: Negative values are allowed too, and a range of values are not required, i.e. [-1, 1] is valid as well as [1,3,5]. =)
|
137
|
+
|
138
|
+
*Advanced*
|
139
|
+
|
140
|
+
* *:total_precision* - maximum number of digits for the average rating value. Default: *1*.
|
141
|
+
* *:step* - useful if you want to specify a custom step for each scale value within a range of values. Default: *1* for range of fixnum, auto-detected based on first value in range of float.
|
142
|
+
* *:steps* - similar to *:step* (they relate to each other), but instead of specifying a step you can specify how many steps you want. Default: auto-detected based on custom or default value *:step*.
|
143
|
+
|
144
|
+
# Aliases
|
145
|
+
|
146
|
+
To make the usage of ActsAsReviewable a bit more generic (similar to other plugins you may use), there are two useful aliases for this purpose:
|
147
|
+
|
148
|
+
* *Review#owner* <=> *Review#reviewer*
|
149
|
+
* *Review#object* <=> *Review#reviewable*
|
150
|
+
|
151
|
+
Example:
|
152
|
+
|
153
|
+
<pre>
|
154
|
+
@post.reviews.first.owner == post.reviews.first.reviewer # => true
|
155
|
+
@post.reviews.first.object == post.reviews.first.reviewable # => true
|
156
|
+
</pre>
|
157
|
+
|
158
|
+
# Finders (Named Scopes)
|
159
|
+
|
160
|
+
ActsAsReviewable has plenty of useful finders implemented using scopes. Here they are:
|
161
|
+
|
162
|
+
## *Review*
|
163
|
+
|
164
|
+
*Order:*
|
165
|
+
|
166
|
+
* *in_order* - most recent reviews last (order by creation date).
|
167
|
+
* *most_recent* - most recent reviews first (opposite of *in_order* above).
|
168
|
+
* *lowest_rating* - reviews with lowest ratings first.
|
169
|
+
* *highest_rating* - reviews with highest ratings first.
|
170
|
+
|
171
|
+
*Filter:*
|
172
|
+
|
173
|
+
* *limit(<number_of_items>)* - maximum *<number_of_items>* reviews.
|
174
|
+
* *since(<created_at_datetime>)* - reviews created since *<created_at_datetime>*.
|
175
|
+
* *recent(<datetime_or_size>)* - if DateTime: reviews created since *<datetime_or_size>*, else if Fixnum: pick last *<datetime_or_size>* number of reviews.
|
176
|
+
* *between_dates(<from_date>, to_date)* - reviews created between two datetimes.
|
177
|
+
* *with_rating(<rating_value_or_range>)* - reviews with(in) rating value (or range) *<rating_value_or_range>*.
|
178
|
+
* *with_a_rating* - reviews with a rating value, i.e. not nil.
|
179
|
+
* *without_a_rating* - opposite of *with_a_rating* (above).
|
180
|
+
* *with_a_body* - reviews with a body/comment, i.e. not nil/blank.
|
181
|
+
* *without_a_body* - opposite of *with_a_body* (above).
|
182
|
+
* *complete* - reviews with both rating and comments, i.e. "full reviews" where.
|
183
|
+
* *of_reviewable_type(<reviewable_type>)* - reviews of *<reviewable_type>* type of reviewable models.
|
184
|
+
* *by_reviewer_type(<reviewer_type>)* - reviews of *<reviewer_type>* type of reviewer models.
|
185
|
+
* *on(<reviewable_object>)* - reviews on the reviewable object *<reviewable_object>* .
|
186
|
+
* *by(<reviewer_object>)* - reviews by the *<reviewer_object>* type of reviewer models.
|
187
|
+
|
188
|
+
## *Reviewable*
|
189
|
+
|
190
|
+
_TODO: Documentation on scopes for Reviewable._
|
191
|
+
|
192
|
+
## *Reviewer*
|
193
|
+
|
194
|
+
_TODO: Documentation on scopes for Reviewer._
|
195
|
+
|
196
|
+
## Examples using finders:
|
197
|
+
|
198
|
+
<pre>
|
199
|
+
@user = User.first
|
200
|
+
@post = Post.first
|
201
|
+
|
202
|
+
@post.reviews.recent(10) # => [10 most recent reviews]
|
203
|
+
@post.reviews.recent(1.week.ago) # => [reviews created since 1 week ago]
|
204
|
+
|
205
|
+
@post.reviews.with_rating(3.5..4.0) # => [all reviews on @post with rating between 3.5 and 4.0]
|
206
|
+
|
207
|
+
@post.reviews.by_reviewer_type(:user) # => [all reviews on @post by User-objects]
|
208
|
+
# ...or:
|
209
|
+
@post.reviews.by_reviewer_type(:users) # => [all reviews on @post by User-objects]
|
210
|
+
# ...or:
|
211
|
+
@post.reviews.by_reviewer_type(User) # => [all reviews on @post by User-objects]
|
212
|
+
|
213
|
+
@user.reviews.on(@post) # => [all reviews by @user on @post]
|
214
|
+
@post.reviews.by(@user) # => [all reviews by @user on @post] (equivalent with above)
|
215
|
+
|
216
|
+
Review.on(@post) # => [all reviews on @user] <=> @post.reviews
|
217
|
+
Review.by(@user) # => [all reviews by @user] <=> @user.reviews
|
218
|
+
|
219
|
+
</pre>
|
220
|
+
|
221
|
+
# Additional Methods
|
222
|
+
|
223
|
+
## Routes
|
224
|
+
|
225
|
+
*config/routes.rb*
|
226
|
+
|
227
|
+
<pre>
|
228
|
+
resources :posts, :member => {:rate => :put}
|
229
|
+
</pre>
|
230
|
+
|
231
|
+
## Views
|
232
|
+
|
233
|
+
ActsAsReviewable comes with no view templates (etc.), but basic rating mechanism is trivial to implement (in this example, I'm using HAML because I despise ERB):
|
234
|
+
|
235
|
+
Example: *app/views/posts/show.html.haml*
|
236
|
+
|
237
|
+
<pre>
|
238
|
+
%h1
|
239
|
+
= @post.title
|
240
|
+
%p
|
241
|
+
= @post.body
|
242
|
+
%p
|
243
|
+
= "Your rating:"
|
244
|
+
#rating_wrapper= render '/reviews/rating', :resource => @post
|
245
|
+
</pre>
|
246
|
+
|
247
|
+
Example: *app/views/reviews/_rating.html.haml*
|
248
|
+
|
249
|
+
<pre>
|
250
|
+
.rating
|
251
|
+
- if resource.present? && resource.reviewable?
|
252
|
+
- if reviewer.present?
|
253
|
+
- current_rating = resource.review_by(reviewer).try(:rating)
|
254
|
+
- resource.reviewable_scale.each do |rating|
|
255
|
+
= link_to_remote "#{rating.to_i}", :url => rate_post_path(resource, :rating => rating.to_i), :method => :put, :html => {:class => "rate rated_#{rating.to_i}#{' current' if current_rating == rating}"}
|
256
|
+
= link_to_remote "no opinion", :url => rate_post_path(resource, :rating => nil), :method => :put, :html => {:class => "rate rated_none#{' current' unless current_rating}"}
|
257
|
+
- else # static rating
|
258
|
+
- current_rating = resource.average_rating.round
|
259
|
+
- resource.reviewable_scale.each do |rating|
|
260
|
+
{:class => "rate rated_#{rating}#{' current' if current_rating == rating}"}
|
261
|
+
</pre>
|
262
|
+
|
263
|
+
## JavaScript/AJAX
|
264
|
+
|
265
|
+
|
266
|
+
Done! =)
|
267
|
+
|
268
|
+
# Additional Use Cases
|
269
|
+
|
270
|
+
## Like/Dislike
|
271
|
+
|
272
|
+
ActsAsReviewable is designed in such way that you as a developer are not locked to how traditional rating works. As an example, this is how you could implement like/dislike (like VoteFu) pattern using ActsAsReviewable:
|
273
|
+
|
274
|
+
Example:
|
275
|
+
|
276
|
+
<pre>
|
277
|
+
class Post < ActiveRecord::Base
|
278
|
+
acts_as_reviewable :by => :users, :values => [0, 1]
|
279
|
+
end
|
280
|
+
</pre>
|
281
|
+
|
282
|
+
*Note:* *:values* is an alias for *:scale* for semantical reasons in cases like these.
|
283
|
+
|
284
|
+
# Dependencies
|
285
|
+
|
286
|
+
For testing: "rspec" and "sqlite3-ruby":http://gemcutter.org/gems/sqlite3-ruby.
|
287
|
+
|
288
|
+
# Notes
|
289
|
+
|
290
|
+
* Tested with Ruby 1.9.2 and Rails 3.0.5.
|
291
|
+
* Let me know if you find any bugs; not used in production yet so consider this a concept version.
|
292
|
+
|
293
|
+
# TODO
|
294
|
+
|
295
|
+
## Priority:
|
296
|
+
|
297
|
+
* bug: Accept , etc..
|
298
|
+
* documentation: A few more README-examples.
|
299
|
+
* feature: Useful finders for *Reviewable*.
|
300
|
+
* feature: Useful finders for *Reviewer*.
|
301
|
+
* testing: More thorough tests, especially for scopes which is a bit tricky.
|
302
|
+
|
303
|
+
## Maybe:
|
304
|
+
|
305
|
+
# Related Links
|
306
|
+
|
307
|
+
...that might be of interest.
|
308
|
+
|
309
|
+
* "jQuery Star Rating":http://github.com/rathgar/jquery-star-rating/ - javascript star rating plugin for Rails on jQuery, if you don't want to do the rating widget on your own. It should be quite straightforward to customize the appearance of it for your needs too.
|
310
|
+
|
311
|
+
|
312
|
+
# Versioning
|
313
|
+
|
314
|
+
This project uses Semantic Versioning -- Please read and use to make the world a better place for software: http://semver.org/
|
315
|
+
|
316
|
+
# License
|
317
|
+
|
318
|
+
Released under the MIT license.
|
319
|
+
Copyright (c) "Eric Steen":http://github.com/rubycoder1
|
320
|
+
|
321
|
+
This project rocks and uses MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
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 'rspec/core'
|
13
|
+
require 'rspec/core/rake_task'
|
14
|
+
|
15
|
+
RSpec::Core::RakeTask.new(:spec)
|
16
|
+
|
17
|
+
task :default => :spec
|
18
|
+
|
19
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
21
|
+
rdoc.title = 'ActsAsReviewable'
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.rdoc_files.include('README.rdoc')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
|
3
|
+
class ActsAsReviewableMigrationGenerator < Rails::Generators::Base
|
4
|
+
include Rails::Generators::Migration
|
5
|
+
desc "run this generator to create reviews"
|
6
|
+
|
7
|
+
def self.source_root
|
8
|
+
@_acts_as_reviewable_source_root ||= File.expand_path("../templates", __FILE__)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.next_migration_number(path)
|
12
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_model_file
|
16
|
+
template "review.rb", "app/models/review.rb"
|
17
|
+
migration_template "create_reviews.rb", "db/migrate/create_reviews.rb"
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateReviews < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :reviews do |t|
|
4
|
+
t.string :title, :limit => 50, :default => ""
|
5
|
+
t.text :review
|
6
|
+
t.references :reviewable, :polymorphic => true
|
7
|
+
t.references :user
|
8
|
+
t.string :role, :default => "reviews"
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :comments, :reviewable_type
|
13
|
+
add_index :comments, :reviewable_id
|
14
|
+
add_index :comments, :user_id
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
drop_table :reviews
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Review < ActiveRecord::Base
|
2
|
+
|
3
|
+
include ActsAsReviewable::Review
|
4
|
+
|
5
|
+
belongs_to :reviewable, :polymorphic => true
|
6
|
+
belongs_to :reviewer, :polymorphic => true
|
7
|
+
|
8
|
+
default_scope :order => 'created_at ASC'
|
9
|
+
|
10
|
+
# NOTE: install the acts_as_votable plugin if you
|
11
|
+
# want votes on reviews.
|
12
|
+
#acts_as_voteable
|
13
|
+
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ActsAsReviewable
|
2
|
+
# including this module into your Review model will give you finders and named scopes
|
3
|
+
# useful for working with Reviews.
|
4
|
+
# The named scopes are:
|
5
|
+
# in_order: Returns reviews in the order they were created (created_at ASC).
|
6
|
+
# recent: Returns reviews by how recently they were created (created_at DESC).
|
7
|
+
# limit(N): Return no more than N reviews.
|
8
|
+
module Review
|
9
|
+
|
10
|
+
def self.included(review_model)
|
11
|
+
review_model.extend Finders
|
12
|
+
review_model.scope :in_order, review_model.order('created_at ASC')
|
13
|
+
review_model.scope :recent, review_model.order('created_at DESC')
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def is_review_type?(type)
|
18
|
+
type.to_s == role.singularize.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
module Finders
|
22
|
+
# Helper class method to lookup all reviews assigned
|
23
|
+
# to all reviewable types for a given user.
|
24
|
+
def find_reviews_by_user(user, role = "reviews")
|
25
|
+
where(["user_id = ? and role = ?", user.id, role]).order("created_at DESC")
|
26
|
+
end
|
27
|
+
|
28
|
+
# Helper class method to look up all reviews for
|
29
|
+
# reviewable class name and reviewable id.
|
30
|
+
def find_reviews_for_reviewable(reviewable_str, reviewable_id, role = "reviews")
|
31
|
+
where(["reviewable_type = ? and reviewable_id = ? and role = ?", reviewable_str, reviewable_id, role]).order("created_at DESC")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Helper class method to look up a reviewable object
|
35
|
+
# given the reviewable class name and id
|
36
|
+
def find_reviewable(reviewable_str, reviewable_id)
|
37
|
+
model = reviewable_str.constantize
|
38
|
+
model.respond_to?(:find_reviews_for) ? model.find(reviewable_id) : nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
# ActsAsReviewable
|
4
|
+
module RapidFire
|
5
|
+
module Acts #:nodoc:
|
6
|
+
module Reviewable #:nodoc:
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def acts_as_reviewable(*args)
|
14
|
+
review_roles = args.to_a.flatten.compact.map(&:to_sym)
|
15
|
+
write_inheritable_attribute(:review_types, (review_roles.blank? ? [:reviews] : review_roles))
|
16
|
+
class_inheritable_reader(:review_types)
|
17
|
+
|
18
|
+
options = ((args.blank? or args[0].blank?) ? {} : args[0])
|
19
|
+
|
20
|
+
if !review_roles.blank?
|
21
|
+
review_roles.each do |role|
|
22
|
+
has_many "#{role.to_s}_reviews".to_sym,
|
23
|
+
{:class_name => "Review",
|
24
|
+
:as => :reviewable,
|
25
|
+
:dependent => :destroy,
|
26
|
+
:conditions => ["role = ?", role.to_s],
|
27
|
+
:before_add => Proc.new { |x, c| c.role = role.to_s }}
|
28
|
+
end
|
29
|
+
else
|
30
|
+
has_many :reviews, {:as => :reviewable, :dependent => :destroy}
|
31
|
+
end
|
32
|
+
|
33
|
+
review_types.each do |role|
|
34
|
+
method_name = (role == :reviews ? "reviews" : "#{role.to_s}_reviews").to_s
|
35
|
+
class_eval %{
|
36
|
+
def self.find_#{method_name}_for(obj)
|
37
|
+
reviewable = self.base_class.name
|
38
|
+
review.find_reviews_for_reviewable(reviewable, obj.id, "#{role.to_s}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.find_#{method_name}_by_user(user)
|
42
|
+
reviewable = self.base_class.name
|
43
|
+
review.where(["user_id = ? and reviewable_type = ? and role = ?", user.id, reviewable, "#{role.to_s}"]).order("created_at DESC")
|
44
|
+
end
|
45
|
+
|
46
|
+
def #{method_name}_ordered_by_submitted
|
47
|
+
review.find_reviews_for_reviewable(self.class.name, id, "#{role.to_s}")
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_#{method_name.singularize}(review)
|
51
|
+
review.role = "#{role.to_s}"
|
52
|
+
#{method_name} << review
|
53
|
+
end
|
54
|
+
}
|
55
|
+
|
56
|
+
include RapidFire::Acts::Reviewable::InstanceMethods
|
57
|
+
end
|
58
|
+
end # def acts_as_reviewable
|
59
|
+
end # module ClassMethods
|
60
|
+
|
61
|
+
module InstanceMethods
|
62
|
+
|
63
|
+
|
64
|
+
end # module InstanceMethods
|
65
|
+
|
66
|
+
end # module Reviewable
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
ActiveRecord::Base.class_eval { include RapidFire::Acts::Reviewable }
|
71
|
+
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_reviewable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ernest Wu
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Reviews for any AR model with multi-dimensional ratings and review commentary.
|
14
|
+
email: wuboys@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/acts_as_reviewable.rb
|
20
|
+
- lib/generators/review/review_generator.rb
|
21
|
+
- lib/generators/review/templates/create_reviews.rb
|
22
|
+
- lib/generators/review/templates/review.rb
|
23
|
+
- lib/generators/review/USAGE
|
24
|
+
- lib/review_methods.rb
|
25
|
+
- lib/reviewable_methods.rb
|
26
|
+
- MIT-LICENSE
|
27
|
+
- Rakefile
|
28
|
+
- Gemfile
|
29
|
+
- README.md
|
30
|
+
homepage:
|
31
|
+
licenses: []
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.9.3
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 2.0.5
|
50
|
+
signing_key:
|
51
|
+
specification_version: 4
|
52
|
+
summary: Reviews for any AR model with multi-dimensional ratings and review commentary.
|
53
|
+
test_files: []
|