ajaxful_rating_jquery 2.2.9
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/CHANGELOG +54 -0
- data/Manifest +20 -0
- data/README.textile +237 -0
- data/Rakefile +15 -0
- data/ajaxful_rating_jquery.gemspec +30 -0
- data/generators/ajaxful_rating/USAGE +5 -0
- data/generators/ajaxful_rating/ajaxful_rating_generator.rb +31 -0
- data/generators/ajaxful_rating/templates/images/star.png +0 -0
- data/generators/ajaxful_rating/templates/images/star_medium.png +0 -0
- data/generators/ajaxful_rating/templates/images/star_small.png +0 -0
- data/generators/ajaxful_rating/templates/migration.rb +18 -0
- data/generators/ajaxful_rating/templates/model.rb +6 -0
- data/generators/ajaxful_rating/templates/style.css +99 -0
- data/init.rb +1 -0
- data/lib/ajaxful_rating_jquery.rb +6 -0
- data/lib/axr/css_builder.rb +30 -0
- data/lib/axr/errors.rb +27 -0
- data/lib/axr/helpers.rb +150 -0
- data/lib/axr/locale.rb +30 -0
- data/lib/axr/model.rb +264 -0
- data/lib/axr/stars_builder.rb +112 -0
- metadata +101 -0
data/CHANGELOG
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
== 2.2.9 Sept 30, 2010
|
|
2
|
+
* Released as a separate ajaxful_rating_jquery gem.
|
|
3
|
+
|
|
4
|
+
== 2.2.8.1 Jul 02, 2010
|
|
5
|
+
* Call html_safe only when it's available.
|
|
6
|
+
|
|
7
|
+
== 2.2.8 Jun 14, 2010
|
|
8
|
+
* Fix html for <li> marking it as html_safe when using rails_xss plugin
|
|
9
|
+
|
|
10
|
+
== 2.2.7 Jun 12, 2010
|
|
11
|
+
* Fix generated html marking it as html_safe when using rails_xss plugin
|
|
12
|
+
|
|
13
|
+
== 2.2.6 May 27, 2010
|
|
14
|
+
* Fix wrapper_dom_id with false values for keys
|
|
15
|
+
|
|
16
|
+
== 2.2.5 May 21, 2010
|
|
17
|
+
* Fix wrapper_dom_id with empty values
|
|
18
|
+
|
|
19
|
+
== 2.2.4 April 15, 2010
|
|
20
|
+
* Fix wrapper_dom_id join options
|
|
21
|
+
|
|
22
|
+
== 2.2.3 March 10, 2010
|
|
23
|
+
* Fix validation of current_user to show linked stars
|
|
24
|
+
|
|
25
|
+
== 2.2.2 March 9, 2010
|
|
26
|
+
* Fix bug for jRuby
|
|
27
|
+
* Fixed user self relational model to be rater and rateable.
|
|
28
|
+
|
|
29
|
+
== 2.2.1 March 8, 2010
|
|
30
|
+
* Changed :force_dynamic for its opposite :force_static.
|
|
31
|
+
* Fixed I18n texts.
|
|
32
|
+
* Fixed missed quotes for Rate belongs_to association with User class
|
|
33
|
+
* Detailed wrapper DOM id with passed hash.
|
|
34
|
+
|
|
35
|
+
== 2.2.0 March 7, 2010
|
|
36
|
+
* Improved model methods and options.
|
|
37
|
+
* Works now with inherited models.
|
|
38
|
+
* Removed HTML and CSS options for helper for sake of simpleness.
|
|
39
|
+
* Renamed helper option :small_stars to :small.
|
|
40
|
+
* Changed whole helper approach. It should work the same as before.
|
|
41
|
+
(Except for the renamed and removed options)
|
|
42
|
+
* Removed :force_dynamic, you should exclude the helper from cache since it uses
|
|
43
|
+
authorization.
|
|
44
|
+
* Fixed opened bugs so far.
|
|
45
|
+
|
|
46
|
+
== 2.1.5 January 28, 2010
|
|
47
|
+
* Renamed options method name to avoid collapse.
|
|
48
|
+
* Removed CSS duplication.
|
|
49
|
+
|
|
50
|
+
== 2.1.4 January 25, 2010
|
|
51
|
+
* Added option for showing current_user's rate instead of global average
|
|
52
|
+
|
|
53
|
+
== 2.1.0 July 25, 2009
|
|
54
|
+
* AjaxfulRating is now available as a gem
|
data/Manifest
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CHANGELOG
|
|
2
|
+
Manifest
|
|
3
|
+
README.textile
|
|
4
|
+
Rakefile
|
|
5
|
+
generators/ajaxful_rating/USAGE
|
|
6
|
+
generators/ajaxful_rating/ajaxful_rating_generator.rb
|
|
7
|
+
generators/ajaxful_rating/templates/images/star.png
|
|
8
|
+
generators/ajaxful_rating/templates/images/star_medium.png
|
|
9
|
+
generators/ajaxful_rating/templates/images/star_small.png
|
|
10
|
+
generators/ajaxful_rating/templates/migration.rb
|
|
11
|
+
generators/ajaxful_rating/templates/model.rb
|
|
12
|
+
generators/ajaxful_rating/templates/style.css
|
|
13
|
+
init.rb
|
|
14
|
+
lib/ajaxful_rating_jquery.rb
|
|
15
|
+
lib/axr/css_builder.rb
|
|
16
|
+
lib/axr/errors.rb
|
|
17
|
+
lib/axr/helpers.rb
|
|
18
|
+
lib/axr/locale.rb
|
|
19
|
+
lib/axr/model.rb
|
|
20
|
+
lib/axr/stars_builder.rb
|
data/README.textile
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
h1. Ajaxful Rating
|
|
2
|
+
|
|
3
|
+
Provides a simple way to add rating functionality to your application. This fork uses jQuery instead of prototype and uses unobtrusive javascript. Currently, it only supports Rails 2.3.x.
|
|
4
|
+
|
|
5
|
+
!http://s3.amazonaws.com/ember/v9SvvO3rdSkA40e1sXBf8JgpuaWCC0uB_o.png!
|
|
6
|
+
|
|
7
|
+
h2. Repository
|
|
8
|
+
|
|
9
|
+
Find it at "github.com/kamui/ajaxful_rating_jquery":http://github.com/kamui/ajaxful_rating_jquery
|
|
10
|
+
|
|
11
|
+
The original repository is located at "github.com/edgarjs/ajaxful-rating":http://github.com/edgarjs/ajaxful-rating
|
|
12
|
+
|
|
13
|
+
h2. Demo
|
|
14
|
+
|
|
15
|
+
I don't have a working demo up of my form but you can see the original version's demo app at "http://github.com/edgarjs/ajaxful-rating_demo_app":http://github.com/edgarjs/ajaxful-rating_demo_app
|
|
16
|
+
Just migrate and run...
|
|
17
|
+
|
|
18
|
+
Or view it live: "http://axr.heroku.com":http://axr.heroku.com
|
|
19
|
+
|
|
20
|
+
*******************************************************************
|
|
21
|
+
|
|
22
|
+
h2. Instructions
|
|
23
|
+
|
|
24
|
+
h3. Install
|
|
25
|
+
|
|
26
|
+
To install the gem run the next command:
|
|
27
|
+
|
|
28
|
+
@gem install ajaxful_rating_jquery@
|
|
29
|
+
|
|
30
|
+
You can configure it in your environment.rb file also:
|
|
31
|
+
|
|
32
|
+
@config.gem "ajaxful_rating_jquery"@
|
|
33
|
+
|
|
34
|
+
h3. Generate
|
|
35
|
+
|
|
36
|
+
@script/generate ajaxful_rating UserModelName@
|
|
37
|
+
|
|
38
|
+
The generator takes one argument: UserModelName, which is the name of your *current*
|
|
39
|
+
user model. This is necessary to link both the rate and user models.
|
|
40
|
+
|
|
41
|
+
Also this generator copies the necessary images, styles, etc.
|
|
42
|
+
|
|
43
|
+
Example:
|
|
44
|
+
_I suppose you have generated already an authenticated model..._
|
|
45
|
+
|
|
46
|
+
<pre>
|
|
47
|
+
script/generate authenticated user sessions
|
|
48
|
+
script/generate ajaxful_rating user
|
|
49
|
+
</pre>
|
|
50
|
+
|
|
51
|
+
So this call will create a Rate model and will link it to your User model.
|
|
52
|
+
|
|
53
|
+
h3. Prepare
|
|
54
|
+
|
|
55
|
+
To let a model be rateable just add @ajaxful_rateable@. You can pass a hash of options to
|
|
56
|
+
customise this call:
|
|
57
|
+
* @:stars@ Max number of stars that can be submitted.
|
|
58
|
+
* @:allow_update@ Set to true if you want users to be able to update their votes.
|
|
59
|
+
* @:cache_column@ Name of the column for storing the cached rating average.
|
|
60
|
+
* @:dimensions@ Array of dimensions. Allows to rate the model on various specs,
|
|
61
|
+
like for example: a car could be rated for its speed, beauty or price.
|
|
62
|
+
|
|
63
|
+
<pre>
|
|
64
|
+
class Car < ActiveRecord::Base
|
|
65
|
+
ajaxful_rateable :stars => 10, :dimensions => [:speed, :beauty, :price]
|
|
66
|
+
end
|
|
67
|
+
</pre>
|
|
68
|
+
|
|
69
|
+
Then you need to add a call @ajaxful_rater@ in the user model to make your @User@ model able to rate objects.
|
|
70
|
+
|
|
71
|
+
<pre>
|
|
72
|
+
class User < ActiveRecord::Base
|
|
73
|
+
ajaxful_rater
|
|
74
|
+
end
|
|
75
|
+
</pre>
|
|
76
|
+
|
|
77
|
+
Finally, as a mere recommendation to make it even easier, modify your routes to
|
|
78
|
+
map a rate action:
|
|
79
|
+
|
|
80
|
+
@map.resources :cars, :member => {:rate => :post}@
|
|
81
|
+
|
|
82
|
+
h3. Use it
|
|
83
|
+
|
|
84
|
+
To add the star links you need to call the helper method @ratings_for@.
|
|
85
|
+
It tries to call @current_user@ method as the rater instance. You can pass @:static@
|
|
86
|
+
as the second param to display only the static stars (not clickables).
|
|
87
|
+
And also you can pass the dimension you want to show the ratings for.
|
|
88
|
+
|
|
89
|
+
<pre>
|
|
90
|
+
#show.html.erb
|
|
91
|
+
<%= ratings_for @article %>
|
|
92
|
+
|
|
93
|
+
#To display static stars:
|
|
94
|
+
<%= ratings_for @article, :static %>
|
|
95
|
+
|
|
96
|
+
#To display the ratings for a dimension:
|
|
97
|
+
<%= ratings_for @article, :dimension => :speed %>
|
|
98
|
+
</pre>
|
|
99
|
+
|
|
100
|
+
Or you can specify a custom user instance by passing it as parameter.
|
|
101
|
+
|
|
102
|
+
<pre>
|
|
103
|
+
<%= ratings_for @article, @user %>
|
|
104
|
+
</pre>
|
|
105
|
+
|
|
106
|
+
By default ratings_for will display the average user rating. If you would like it to
|
|
107
|
+
display the rating for the current_user, then set the :show_user_rating parameter to true.
|
|
108
|
+
For example:
|
|
109
|
+
|
|
110
|
+
<pre>
|
|
111
|
+
# To display the rating for the current user (current_user):
|
|
112
|
+
<%= ratings_for @article, :show_user_rating => true %>
|
|
113
|
+
|
|
114
|
+
# To change the size of the stars you can also specify an optional :size value. If none is set it uses the large size, otherwise you can specify medium or small:
|
|
115
|
+
<%= ratings_for @article, :size => "medium" %>
|
|
116
|
+
|
|
117
|
+
# To display the rating for the user specified by @user:
|
|
118
|
+
<%= ratings_for @article, @user, :show_user_rating => true %>
|
|
119
|
+
</pre>
|
|
120
|
+
|
|
121
|
+
There's a condition here, if you didn't add the route @rate@ to your resource
|
|
122
|
+
(as shown above) or you named it different, you'll need to pass the url to the
|
|
123
|
+
correct action in your controller:
|
|
124
|
+
|
|
125
|
+
<pre>
|
|
126
|
+
<%= ratings_for @article, :url => your_rate_path(@article) %>
|
|
127
|
+
</pre>
|
|
128
|
+
|
|
129
|
+
+h3. Important!
|
|
130
|
+
|
|
131
|
+
*To display the stars properly you need to add a call in the head of your layout, which will generate the
|
|
132
|
+
required CSS style for the list. Also don't forget to include jQ--uery.*
|
|
133
|
+
|
|
134
|
+
It's also important to note that this call MUST be within your head tags in your layout, as for now it seems to doesn't work with the @content_for@ tag.
|
|
135
|
+
|
|
136
|
+
<pre>
|
|
137
|
+
#within the head tags of your layout...
|
|
138
|
+
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" %>
|
|
139
|
+
<%= ajaxful_rating_style %>
|
|
140
|
+
<%= ajaxful_rating_script %>
|
|
141
|
+
</pre>
|
|
142
|
+
|
|
143
|
+
When a user submits a rating it will call the action in your controller, for
|
|
144
|
+
example (if you added the @rate@ route):
|
|
145
|
+
|
|
146
|
+
<pre>
|
|
147
|
+
def rate
|
|
148
|
+
@car = Car.find(params[:id])
|
|
149
|
+
@car.rate(params[:stars], current_user, params[:dimension])
|
|
150
|
+
average = @product.rate_average(true, params[:dimension])
|
|
151
|
+
width = (average / @car.class.max_stars.to_f) * 100
|
|
152
|
+
render :json => {:id => @car.wrapper_dom_id(params), :average => average, :width => width}
|
|
153
|
+
end
|
|
154
|
+
</pre>
|
|
155
|
+
|
|
156
|
+
There are some more options for this helper, please see the rdoc for details.
|
|
157
|
+
|
|
158
|
+
h3. Dimensions
|
|
159
|
+
|
|
160
|
+
From now on you can pass an optional parameter to the @rates@ method for your rateable object to retrieve the
|
|
161
|
+
corresponding rates for the dimension you want.
|
|
162
|
+
|
|
163
|
+
For example, you defined these dimensions:
|
|
164
|
+
|
|
165
|
+
<pre>
|
|
166
|
+
class Car < ActiveRecord::Base
|
|
167
|
+
ajaxful_rateable :dimensions => [:speed, :beauty, :price]
|
|
168
|
+
end
|
|
169
|
+
</pre>
|
|
170
|
+
|
|
171
|
+
And hence you can call @car.rates(:price)@ for the price rates or @car.rates(:speed)@ for the speed ratings and so on.
|
|
172
|
+
|
|
173
|
+
h3. Namespaces
|
|
174
|
+
|
|
175
|
+
If you use the plugin inside a namespace you’ll need to specify the rating url which should points to
|
|
176
|
+
a controller inside a namespace. Your files should be like these:
|
|
177
|
+
|
|
178
|
+
<pre>
|
|
179
|
+
routes.rb:
|
|
180
|
+
map.namespace :admin do |admin|
|
|
181
|
+
admin.resources :articles, :member => {:rate => :post}
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
views/admin/articles/show.html.erb
|
|
185
|
+
<%= ratings_for @article, :url => rate_admin_article_path(@article) %>
|
|
186
|
+
</pre>
|
|
187
|
+
|
|
188
|
+
h3. Cache
|
|
189
|
+
|
|
190
|
+
To cache the model's rating average add a column named @rating_average@ to your model table:
|
|
191
|
+
|
|
192
|
+
<pre>
|
|
193
|
+
class AddRatingAverageToArticles < ActiveRecord::Migration
|
|
194
|
+
def self.up
|
|
195
|
+
add_column :articles, :rating_average, :decimal, :default => 0, :precision => 6, :scale => 2
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def self.down
|
|
199
|
+
remove_column :articles, :rating_average
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
</pre>
|
|
203
|
+
|
|
204
|
+
If you want to customize the name of the cache column just pass it in the options hash:
|
|
205
|
+
|
|
206
|
+
<pre>
|
|
207
|
+
class Article < ActiveRecord::Base
|
|
208
|
+
ajaxful_rateable :cache_column => :my_cached_rating
|
|
209
|
+
end
|
|
210
|
+
</pre>
|
|
211
|
+
|
|
212
|
+
To use caching with dimensions, make sure you have a cache column defined for each dimension you want cached.
|
|
213
|
+
So if you want to cache the @spelling@ dimension, you’ll need to have a column called @rating_average_spelling@ on the articles table.
|
|
214
|
+
If you use a custom cache column name, follow the pattern @cache_column_name_dimension_name@ to add cache columns for dimensions.
|
|
215
|
+
|
|
216
|
+
h2. Feedback
|
|
217
|
+
|
|
218
|
+
If you find bugs please open a ticket at "http://github.com/kamui/ajaxful_rating_jquery/issues":http://github.com/kamui/ajaxful_rating_jquery/issues
|
|
219
|
+
|
|
220
|
+
I'll really appreciate your feedback, please contact me at kamuigt[at]gmail[dot]com
|
|
221
|
+
|
|
222
|
+
h2. Credits
|
|
223
|
+
|
|
224
|
+
The original developer of ajaxify_rating, "Edgar J. Suarez":http://github.com/edgarjs
|
|
225
|
+
|
|
226
|
+
The helper's style is from "komodomedia":http://www.komodomedia.com/blog/2007/01/css-star-rating-redux/ with author's permission.
|
|
227
|
+
|
|
228
|
+
If you need the psd files of the stars you can grab them "here":http://aws3-edgarjs-zips.s3.amazonaws.com/ajaxful_rating_stars.zip
|
|
229
|
+
|
|
230
|
+
Thanks to "bborn":http://github.com/bborn for the dimensions base implementation.
|
|
231
|
+
|
|
232
|
+
h2. License
|
|
233
|
+
|
|
234
|
+
This code is released under Creative Commons Attribution-Share Alike 3.0 license.
|
|
235
|
+
|
|
236
|
+
!http://i.creativecommons.org/l/by-sa/3.0/88x31.png!:http://creativecommons.org/licenses/by-sa/3.0/
|
|
237
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
require 'echoe'
|
|
4
|
+
|
|
5
|
+
Echoe.new('ajaxful_rating_jquery', '2.2.9') do |p|
|
|
6
|
+
p.summary = "Add star rating functionality to your Rails 2.3.x application. Requires jQuery."
|
|
7
|
+
p.description = "Provides a simple way to add rating functionality to your application. This is a fork of ajaxful_ratings that works with jQuery instead of Prototype and uses unobtrusive javascript instead of link_to_remote."
|
|
8
|
+
p.url = "http://github.com/kamui/ajaxful_rating_jquery"
|
|
9
|
+
p.author = "Jack Chu, Edgar J. Suarez"
|
|
10
|
+
p.email = "kamuigt@gmail.com"
|
|
11
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
|
12
|
+
p.development_dependencies = []
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{ajaxful_rating_jquery}
|
|
5
|
+
s.version = "2.2.9"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Jack Chu, Edgar J. Suarez"]
|
|
9
|
+
s.date = %q{2010-09-30}
|
|
10
|
+
s.description = %q{Provides a simple way to add rating functionality to your application. This is a fork of ajaxful_ratings that works with jQuery instead of Prototype and uses unobtrusive javascript instead of link_to_remote.}
|
|
11
|
+
s.email = %q{kamuigt@gmail.com}
|
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "README.textile", "lib/ajaxful_rating_jquery.rb", "lib/axr/css_builder.rb", "lib/axr/errors.rb", "lib/axr/helpers.rb", "lib/axr/locale.rb", "lib/axr/model.rb", "lib/axr/stars_builder.rb"]
|
|
13
|
+
s.files = ["CHANGELOG", "Manifest", "README.textile", "Rakefile", "generators/ajaxful_rating/USAGE", "generators/ajaxful_rating/ajaxful_rating_generator.rb", "generators/ajaxful_rating/templates/images/star.png", "generators/ajaxful_rating/templates/images/star_medium.png", "generators/ajaxful_rating/templates/images/star_small.png", "generators/ajaxful_rating/templates/migration.rb", "generators/ajaxful_rating/templates/model.rb", "generators/ajaxful_rating/templates/style.css", "init.rb", "lib/ajaxful_rating_jquery.rb", "lib/axr/css_builder.rb", "lib/axr/errors.rb", "lib/axr/helpers.rb", "lib/axr/locale.rb", "lib/axr/model.rb", "lib/axr/stars_builder.rb", "ajaxful_rating_jquery.gemspec"]
|
|
14
|
+
s.homepage = %q{http://github.com/kamui/ajaxful_rating_jquery}
|
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Ajaxful_rating_jquery", "--main", "README.textile"]
|
|
16
|
+
s.require_paths = ["lib"]
|
|
17
|
+
s.rubyforge_project = %q{ajaxful_rating_jquery}
|
|
18
|
+
s.rubygems_version = %q{1.3.7}
|
|
19
|
+
s.summary = %q{Add star rating functionality to your Rails 2.3.x application. Requires jQuery.}
|
|
20
|
+
|
|
21
|
+
if s.respond_to? :specification_version then
|
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
23
|
+
s.specification_version = 3
|
|
24
|
+
|
|
25
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
26
|
+
else
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class AjaxfulRatingGenerator < Rails::Generator::NamedBase
|
|
2
|
+
def initialize(runtime_args, runtime_options = {})
|
|
3
|
+
super
|
|
4
|
+
|
|
5
|
+
# if there's no user model
|
|
6
|
+
model_file = File.join('app/models', "#{file_path}.rb")
|
|
7
|
+
raise "User model (#{model_file}) must exits." unless File.exists?(model_file)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def manifest
|
|
11
|
+
record do |m|
|
|
12
|
+
m.class_collisions 'Rate'
|
|
13
|
+
m.template 'model.rb', File.join('app/models', 'rate.rb')
|
|
14
|
+
m.migration_template 'migration.rb', 'db/migrate',
|
|
15
|
+
:migration_file_name => 'create_rates'
|
|
16
|
+
|
|
17
|
+
# style
|
|
18
|
+
m.directory 'public/images/ajaxful_rating'
|
|
19
|
+
m.file 'images/star.png', 'public/images/ajaxful_rating/star.png'
|
|
20
|
+
m.file 'images/star_medium.png', 'public/images/ajaxful_rating/star_medium.png'
|
|
21
|
+
m.file 'images/star_small.png', 'public/images/ajaxful_rating/star_small.png'
|
|
22
|
+
m.file 'style.css', 'public/stylesheets/ajaxful_rating.css'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
def banner
|
|
29
|
+
"Usage: #{$0} ajaxful_rating UserModelName"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class CreateRates < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :rates do |t|
|
|
4
|
+
t.belongs_to :rater
|
|
5
|
+
t.belongs_to :rateable, :polymorphic => true
|
|
6
|
+
t.integer :stars, :null => false
|
|
7
|
+
t.string :dimension
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :rates, :rater_id
|
|
12
|
+
add_index :rates, [:rateable_id, :rateable_type]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.down
|
|
16
|
+
drop_table :rates
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Style by Rogie http://www.komodomedia.com/blog/2007/01/css-star-rating-redux/
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
.ajaxful-rating,
|
|
6
|
+
.ajaxful-rating a:hover,
|
|
7
|
+
.ajaxful-rating a:active,
|
|
8
|
+
.ajaxful-rating a:focus,
|
|
9
|
+
.ajaxful-rating .show-value{
|
|
10
|
+
background: url(/images/ajaxful_rating/star.png) left -1000px repeat-x;
|
|
11
|
+
}
|
|
12
|
+
.ajaxful-rating{
|
|
13
|
+
position: relative;
|
|
14
|
+
/*width: 125px; this is setted dynamically */
|
|
15
|
+
height: 25px;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
list-style: none;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
background-position: left top;
|
|
21
|
+
}
|
|
22
|
+
.ajaxful-rating li{ display: inline; }
|
|
23
|
+
.ajaxful-rating a,
|
|
24
|
+
.ajaxful-rating span,
|
|
25
|
+
.ajaxful-rating .show-value{
|
|
26
|
+
position: absolute;
|
|
27
|
+
top: 0;
|
|
28
|
+
left: 0;
|
|
29
|
+
text-indent: -1000em;
|
|
30
|
+
height: 25px;
|
|
31
|
+
line-height: 25px;
|
|
32
|
+
outline: none;
|
|
33
|
+
overflow: hidden;
|
|
34
|
+
border: none;
|
|
35
|
+
}
|
|
36
|
+
.ajaxful-rating a:hover,
|
|
37
|
+
.ajaxful-rating a:active,
|
|
38
|
+
.ajaxful-rating a:focus{
|
|
39
|
+
background-position: left bottom;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* This section is generated dynamically.
|
|
43
|
+
Just add a call to the helper method 'ajaxful_rating_style' within
|
|
44
|
+
the head tags in your main layout
|
|
45
|
+
.ajaxful-rating .stars-1{
|
|
46
|
+
width: 20%;
|
|
47
|
+
z-index: 6;
|
|
48
|
+
}
|
|
49
|
+
.ajaxful-rating .stars-2{
|
|
50
|
+
width: 40%;
|
|
51
|
+
z-index: 5;
|
|
52
|
+
}
|
|
53
|
+
.ajaxful-rating .stars-3{
|
|
54
|
+
width: 60%;
|
|
55
|
+
z-index: 4;
|
|
56
|
+
}
|
|
57
|
+
.ajaxful-rating .stars-4{
|
|
58
|
+
width: 80%;
|
|
59
|
+
z-index: 3;
|
|
60
|
+
}
|
|
61
|
+
.ajaxful-rating .stars-5{
|
|
62
|
+
width: 100%;
|
|
63
|
+
z-index: 2;
|
|
64
|
+
}
|
|
65
|
+
*/
|
|
66
|
+
.ajaxful-rating .show-value{
|
|
67
|
+
z-index: 1;
|
|
68
|
+
background-position: left center;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* medium star */
|
|
72
|
+
.ajaxful-rating.medium{
|
|
73
|
+
/*width: 54px; this is setted dynamically */
|
|
74
|
+
height: 18px;
|
|
75
|
+
}
|
|
76
|
+
.ajaxful-rating.medium,
|
|
77
|
+
.ajaxful-rating.medium a:hover,
|
|
78
|
+
.ajaxful-rating.medium a:active,
|
|
79
|
+
.ajaxful-rating.medium a:focus,
|
|
80
|
+
.ajaxful-rating.medium .show-value{
|
|
81
|
+
background-image: url(/images/ajaxful_rating/star_medium.png);
|
|
82
|
+
line-height: 18px;
|
|
83
|
+
height: 18px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* smaller star */
|
|
87
|
+
.ajaxful-rating.small{
|
|
88
|
+
/*width: 50px; this is setted dynamically */
|
|
89
|
+
height: 10px;
|
|
90
|
+
}
|
|
91
|
+
.ajaxful-rating.small,
|
|
92
|
+
.ajaxful-rating.small a:hover,
|
|
93
|
+
.ajaxful-rating.small a:active,
|
|
94
|
+
.ajaxful-rating.small a:focus,
|
|
95
|
+
.ajaxful-rating.small .show-value{
|
|
96
|
+
background-image: url(/images/ajaxful_rating/star_small.png);
|
|
97
|
+
line-height: 10px;
|
|
98
|
+
height: 10px;
|
|
99
|
+
}
|
data/init.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'ajaxful_rating_jquery'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module AjaxfulRating # :nodoc:
|
|
2
|
+
class CSSBuilder
|
|
3
|
+
attr_reader :rules
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@rules = {}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def rule(selector, attrs)
|
|
10
|
+
@rules[selector] = self.class.stringify_properties(attrs) unless @rules.has_key?(selector)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_css
|
|
14
|
+
css = ''
|
|
15
|
+
@rules.each do |key, value|
|
|
16
|
+
css << "#{key} {#{value}}\n"
|
|
17
|
+
end
|
|
18
|
+
css
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.stringify_properties(properties)
|
|
22
|
+
css = ''
|
|
23
|
+
properties.each do |key, value|
|
|
24
|
+
value = value.is_a?(Fixnum) || value.is_a?(Float) ? "#{value}px" : value
|
|
25
|
+
css << "#{key.to_s.underscore.dasherize}: #{value}; "
|
|
26
|
+
end
|
|
27
|
+
css
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/axr/errors.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module AjaxfulRating # :nodoc:
|
|
2
|
+
module Errors
|
|
3
|
+
class AlreadyRatedError < StandardError
|
|
4
|
+
def to_s
|
|
5
|
+
"Model has already been rated by this user. To allow update of ratings pass :allow_update => true to the ajaxful_rateable call."
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class MissingRateRoute < StandardError
|
|
10
|
+
def to_s
|
|
11
|
+
"Add a member route to your routes file for rate with :post method. Or specify a custom url in the options."
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class NoUserSpecified < StandardError
|
|
16
|
+
def to_s
|
|
17
|
+
"You need to specify a user instance or create a helper with the name current_user."
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class MissingStarsCSSBuilder < StandardError
|
|
22
|
+
def to_s
|
|
23
|
+
"Add a call to ajaxful_rating_style within the head of your layout."
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/axr/helpers.rb
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
module AjaxfulRating # :nodoc:
|
|
2
|
+
module Helpers
|
|
3
|
+
include AjaxfulRating::Errors
|
|
4
|
+
|
|
5
|
+
# Outputs the required css file, and the dynamic CSS generated for the
|
|
6
|
+
# current page.
|
|
7
|
+
def ajaxful_rating_style
|
|
8
|
+
@axr_css ||= CSSBuilder.new
|
|
9
|
+
stylesheet_link_tag('ajaxful_rating') +
|
|
10
|
+
content_tag(:style, @axr_css.to_css, :type => "text/css")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def ajaxful_rating_script
|
|
14
|
+
if protect_against_forgery?
|
|
15
|
+
authenticity_script = %{
|
|
16
|
+
csrf_param = "authenticity_token";
|
|
17
|
+
csrf_token = #{form_authenticity_token.inspect};
|
|
18
|
+
|
|
19
|
+
// Always send the authenticity_token with ajax
|
|
20
|
+
$(document).ajaxSend(function(event, request, settings) {
|
|
21
|
+
if ( settings.type == 'post' ) {
|
|
22
|
+
settings.data = (settings.data ? settings.data + "&" : "")
|
|
23
|
+
+ encodeURIComponent( csrf_param ) + "=" + encodeURIComponent( csrf_token );
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
%{<script>
|
|
30
|
+
#{authenticity_script}
|
|
31
|
+
|
|
32
|
+
$(document).ready(function(){
|
|
33
|
+
$('.ajaxful-rating a').bind('click',function(event){
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
$.ajax({
|
|
36
|
+
type: $(this).attr('data-method'),
|
|
37
|
+
url: $(this).attr('href'),
|
|
38
|
+
data: {
|
|
39
|
+
stars: $(this).attr('data-stars'),
|
|
40
|
+
dimension: $(this).attr('data-dimension'),
|
|
41
|
+
size: $(this).attr('data-size'),
|
|
42
|
+
show_user_rating: $(this).attr('data-show_user_rating')
|
|
43
|
+
},
|
|
44
|
+
success: function(response){
|
|
45
|
+
$('#' + response.id + ' .show-value').css('width', response.width + '%');
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
</script>}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def ajaxful_rating_script_prototype
|
|
54
|
+
%{
|
|
55
|
+
$$('.ajaxful-rating a').observe('click', rateProduct);
|
|
56
|
+
|
|
57
|
+
function rateProduct(event) {
|
|
58
|
+
var element = event.element();
|
|
59
|
+
|
|
60
|
+
new Ajax.Request(element.readAttribute('data-url'), {
|
|
61
|
+
method: element.readAttribute('data-method'),
|
|
62
|
+
parameters: {
|
|
63
|
+
data-stars: element.readAttribute('data-stars'),
|
|
64
|
+
data-dimension: element.readAttribute('data-dimension'),
|
|
65
|
+
data-size: element.readAttribute('data-size'),
|
|
66
|
+
data-show_user_rating: element.readAttribute('data-show_user_rating')
|
|
67
|
+
},
|
|
68
|
+
onSuccess: function(transport, json){
|
|
69
|
+
alert(json ? Object.inspect(json) : "no JSON object");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Generates the stars list to submit a rate.
|
|
77
|
+
#
|
|
78
|
+
# It accepts the next options:
|
|
79
|
+
# * <tt>:size</tt> Set this param to medium or small to display medium/small images. Default is false.
|
|
80
|
+
# Default is {:method => :post, :url => rate_rateablemodel_path(rateable)}.
|
|
81
|
+
# * <tt>:wrap</tt> Whether the star list is wrapped within a div tag or not. This is useful when page updating. Default is true.
|
|
82
|
+
# * <tt>:show_user_rating</tt> Set to true if you want to display only the current user's rating, instead of the global average.
|
|
83
|
+
# * <tt>:dimension</tt> The dimension to show the ratings for.
|
|
84
|
+
# * <tt>:force_static</tt> Force static stars even when you're passing a user instance.
|
|
85
|
+
#
|
|
86
|
+
# Example:
|
|
87
|
+
# <%= ratings_for @article, :wrap => false %> # => Will produce something like:
|
|
88
|
+
# <ul class="ajaxful-rating">
|
|
89
|
+
# <li class="current-rating" style="width: 60%;">3</li>
|
|
90
|
+
# <li><%= link_to_remote 1, :url => rate_article_path(@article, :stars => 1), :method => :post, :html => {:class => 'stars-1', :title => '1 star out of 5'} %></li>
|
|
91
|
+
# <li><%= link_to_remote 2, :url => rate_article_path(@article, :stars => 2), :method => :post, :html => {:class => 'stars-2', :title => '2 stars out of 5'} %></li>
|
|
92
|
+
# <li><%= link_to_remote 3, :url => rate_article_path(@article, :stars => 3), :method => :post, :html => {:class => 'stars-3', :title => '3 stars out of 5'} %></li>
|
|
93
|
+
# <li><%= link_to_remote 4, :url => rate_article_path(@article, :stars => 4), :method => :post, :html => {:class => 'stars-4', :title => '4 stars out of 5'} %></li>
|
|
94
|
+
# <li><%= link_to_remote 5, :url => rate_article_path(@article, :stars => 5), :method => :post, :html => {:class => 'stars-5', :title => '5 stars out of 5'} %></li>
|
|
95
|
+
# </ul>
|
|
96
|
+
#
|
|
97
|
+
# It will try to use the method <tt>current_user</tt> as the user instance. You can specify a custom instance in the second parameter
|
|
98
|
+
# or pass <tt>:static</tt> to leave the list of stars static.
|
|
99
|
+
#
|
|
100
|
+
# Example:
|
|
101
|
+
# <%= ratings_for @article, @user, :size => 'small' %>
|
|
102
|
+
# # => Will use @user instead <tt>current_user</tt>
|
|
103
|
+
#
|
|
104
|
+
# <%= ratings_for @article, :static, :size => 'medium' %>
|
|
105
|
+
# # => Will produce a static list of stars showing the current rating average for @article.
|
|
106
|
+
#
|
|
107
|
+
# The user passed here will *not* be the one who submits the rate. It will be used only for the display behavior of the stars.
|
|
108
|
+
# Like for example, if there is a user logged in or if the current logged in user is able to submit a rate depending on the
|
|
109
|
+
# configuration (accepts update of rates, etc).
|
|
110
|
+
#
|
|
111
|
+
# So to actually set the user who will rate the model you need to do it in your controller:
|
|
112
|
+
#
|
|
113
|
+
# # controller
|
|
114
|
+
# def rate
|
|
115
|
+
# @article = Article.find(params[:id])
|
|
116
|
+
# @article.rate(params[:stars], current_user) # or any user instance
|
|
117
|
+
# # update page, etc.
|
|
118
|
+
# end
|
|
119
|
+
#
|
|
120
|
+
# By default ratings_for will render the average rating for all users. If however you would like to display the rating for a single user, then set the :show_user_rating option to true.
|
|
121
|
+
# For example:
|
|
122
|
+
#
|
|
123
|
+
# <%= ratings_for @article, :show_user_rating => true %>
|
|
124
|
+
# Or
|
|
125
|
+
# <%= ratings_for @article, @user, :show_user_rating => true %>
|
|
126
|
+
#
|
|
127
|
+
# I18n:
|
|
128
|
+
#
|
|
129
|
+
# You can translate the title of the images (the tool tip that shows when the mouse is over) and the 'Currently x/x stars'
|
|
130
|
+
# string by setting these keys on your translation hash:
|
|
131
|
+
#
|
|
132
|
+
# ajaxful_rating:
|
|
133
|
+
# helper:
|
|
134
|
+
# global_average: "Global rating average: {{value}} out of {{max}}"
|
|
135
|
+
# user_rating: "Your rating: {{value}} out of {{max}}"
|
|
136
|
+
# hover: "Rate {{value}} out of {{max}}" def ratings_for(*args)
|
|
137
|
+
def ratings_for(*args)
|
|
138
|
+
@axr_css ||= CSSBuilder.new
|
|
139
|
+
options = args.extract_options!.symbolize_keys.slice(:size, :url, :method,
|
|
140
|
+
:wrap, :show_user_rating, :dimension, :force_static, :current_user)
|
|
141
|
+
rateable = args.shift
|
|
142
|
+
user = args.shift || (respond_to?(:current_user) ? current_user : raise(NoUserSpecified))
|
|
143
|
+
StarsBuilder.new(rateable, user, self, @axr_css, options).render
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
class ActionView::Base # :nodoc:
|
|
149
|
+
include AjaxfulRating::Helpers
|
|
150
|
+
end
|
data/lib/axr/locale.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module AjaxfulRating # :nodoc:
|
|
2
|
+
|
|
3
|
+
# Customize messages by adding I18n keys:
|
|
4
|
+
#
|
|
5
|
+
# ajaxful_rating:
|
|
6
|
+
# helper:
|
|
7
|
+
# global_average: "Global rating average: {{value}} out of {{max}}"
|
|
8
|
+
# user_rating: "Your rating: {{value}} out of {{max}}"
|
|
9
|
+
# hover: "Rate {{value}} out of {{max}}"
|
|
10
|
+
module Locale
|
|
11
|
+
|
|
12
|
+
DEFAULTS = {
|
|
13
|
+
:user_rating => "Your rating: {{value}} out of {{max}}",
|
|
14
|
+
:global_average => "Global rating average: {{value}} out of {{max}}",
|
|
15
|
+
:hover => "Rate {{value}} out of {{max}}"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
def i18n(key, value = nil)
|
|
19
|
+
key = if key == :current
|
|
20
|
+
options[:show_user_rating] ? :user_rating : :global_average
|
|
21
|
+
else
|
|
22
|
+
key.to_sym
|
|
23
|
+
end
|
|
24
|
+
default = DEFAULTS[key]
|
|
25
|
+
key = "ajaxful_rating.helper.#{key}"
|
|
26
|
+
I18n.t(key, :value => (value || show_value),
|
|
27
|
+
:max => rateable.class.max_stars, :default => default)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/axr/model.rb
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
module AjaxfulRating # :nodoc:
|
|
2
|
+
include AjaxfulRating::Errors
|
|
3
|
+
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
# Extends the model to be easy ajaxly rateable.
|
|
10
|
+
#
|
|
11
|
+
# Options:
|
|
12
|
+
# * <tt>:stars</tt> Max number of stars that can be submitted.
|
|
13
|
+
# * <tt>:allow_update</tt> Set to true if you want users to be able to update their votes.
|
|
14
|
+
# * <tt>:cache_column</tt> Name of the column for storing the cached rating average.
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
# class Article < ActiveRecord::Base
|
|
18
|
+
# ajaxful_rateable :stars => 10, :cache_column => :custom_column
|
|
19
|
+
# end
|
|
20
|
+
def ajaxful_rateable(options = {})
|
|
21
|
+
has_many :rates_without_dimension, :as => :rateable, :class_name => 'Rate',
|
|
22
|
+
:dependent => :destroy, :conditions => {:dimension => nil}
|
|
23
|
+
has_many :raters_without_dimension, :through => :rates_without_dimension, :source => :rater
|
|
24
|
+
|
|
25
|
+
options[:dimensions].each do |dimension|
|
|
26
|
+
has_many "#{dimension}_rates", :dependent => :destroy,
|
|
27
|
+
:conditions => {:dimension => dimension.to_s}, :class_name => 'Rate', :as => :rateable
|
|
28
|
+
has_many "#{dimension}_raters", :through => "#{dimension}_rates", :source => :rater
|
|
29
|
+
end if options[:dimensions].is_a?(Array)
|
|
30
|
+
|
|
31
|
+
class << self
|
|
32
|
+
def axr_config
|
|
33
|
+
@axr_config ||= {
|
|
34
|
+
:stars => 5,
|
|
35
|
+
:allow_update => true,
|
|
36
|
+
:cache_column => :rating_average
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
alias_method :ajaxful_rating_options, :axr_config
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
axr_config.update(options)
|
|
44
|
+
|
|
45
|
+
include AjaxfulRating::InstanceMethods
|
|
46
|
+
extend AjaxfulRating::SingletonMethods
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Makes the association between user and Rate model.
|
|
50
|
+
def ajaxful_rater(options = {})
|
|
51
|
+
has_many :ratings_given, options.merge(:class_name => "Rate", :foreign_key => :rater_id)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Instance methods for the rateable object.
|
|
56
|
+
module InstanceMethods
|
|
57
|
+
|
|
58
|
+
# Proxy for axr_config singleton method.
|
|
59
|
+
def axr_config
|
|
60
|
+
self.class.axr_config
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Submits a new rate. Accepts a hash of tipical Ajax request.
|
|
64
|
+
#
|
|
65
|
+
# Example:
|
|
66
|
+
# # Articles Controller
|
|
67
|
+
# def rate
|
|
68
|
+
# @article = Article.find(params[:id])
|
|
69
|
+
# @article.rate(params[:stars], current_user, params[:dimension])
|
|
70
|
+
# # some page update here ...
|
|
71
|
+
# end
|
|
72
|
+
def rate(stars, user, dimension = nil)
|
|
73
|
+
return false if (stars.to_i > self.class.max_stars)
|
|
74
|
+
raise AlreadyRatedError if (!self.class.axr_config[:allow_update] && rated_by?(user, dimension))
|
|
75
|
+
|
|
76
|
+
rate = if self.class.axr_config[:allow_update] && rated_by?(user, dimension)
|
|
77
|
+
rate_by(user, dimension)
|
|
78
|
+
else
|
|
79
|
+
returning rates(dimension).build do |r|
|
|
80
|
+
r.rater = user
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
rate.stars = stars
|
|
84
|
+
rate.save!
|
|
85
|
+
self.update_cached_average(dimension)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Builds the DOM id attribute for the wrapper in view.
|
|
89
|
+
def wrapper_dom_id(options = {})
|
|
90
|
+
options = options.symbolize_keys.slice(:size, :dimension)
|
|
91
|
+
options = options.select { |k, v| v.present? or (v == false) }.map do |k, v|
|
|
92
|
+
if k == :dimension
|
|
93
|
+
v.to_s
|
|
94
|
+
else
|
|
95
|
+
v.to_s == 'true' ? k.to_s : "no-#{k}"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
options.unshift("ajaxful_rating")
|
|
99
|
+
ApplicationController.helpers.dom_id(self, options.sort.join('_'))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Returns an array with the users that have rated this object for the
|
|
103
|
+
# passed dimension.
|
|
104
|
+
#
|
|
105
|
+
# It may works as an alias for +dimension_raters+ methods.
|
|
106
|
+
def raters(dimension = nil)
|
|
107
|
+
sql = "SELECT DISTINCT u.* FROM #{self.class.user_class.table_name} u "\
|
|
108
|
+
"INNER JOIN rates r ON u.id = r.rater_id WHERE "
|
|
109
|
+
|
|
110
|
+
sql << self.class.send(:sanitize_sql_for_conditions, {
|
|
111
|
+
:rateable_id => id,
|
|
112
|
+
:rateable_type => self.class.base_class.name,
|
|
113
|
+
:dimension => (dimension.to_s if dimension)
|
|
114
|
+
}, 'r')
|
|
115
|
+
|
|
116
|
+
self.class.user_class.find_by_sql(sql)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Finds the rate made by the user if he/she has already voted.
|
|
120
|
+
def rate_by(user, dimension = nil)
|
|
121
|
+
rates(dimension).find_by_rater_id(user.id)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Return true if the user has rated the object, otherwise false
|
|
125
|
+
def rated_by?(user, dimension = nil)
|
|
126
|
+
!rate_by(user, dimension).nil?
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Returns whether or not the user can rate this object.
|
|
130
|
+
# Based on if the user has already rated the object or the
|
|
131
|
+
# :allow_update option is enabled.
|
|
132
|
+
def can_rate_by?(user, dimension = nil)
|
|
133
|
+
!rated_by?(user, dimension) || self.class.axr_config[:allow_update]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Instance's total rates.
|
|
137
|
+
def total_rates(dimension = nil)
|
|
138
|
+
rates(dimension).size
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Total sum of the rates.
|
|
142
|
+
def rates_sum(dimension = nil)
|
|
143
|
+
rates(dimension).sum(:stars)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Rating average for the object.
|
|
147
|
+
#
|
|
148
|
+
# Pass false as param to force the calculation if you are caching it.
|
|
149
|
+
def rate_average(cached = true, dimension = nil)
|
|
150
|
+
avg = if cached && self.class.caching_average?(dimension)
|
|
151
|
+
send(caching_column_name(dimension)).to_f
|
|
152
|
+
else
|
|
153
|
+
self.rates_sum(dimension).to_f / self.total_rates(dimension).to_f
|
|
154
|
+
end
|
|
155
|
+
avg.nan? ? 0.0 : avg
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Overrides the default +rates+ method and returns the propper array
|
|
159
|
+
# for the dimension passed.
|
|
160
|
+
#
|
|
161
|
+
# It may works as an alias for +dimension_rates+ methods.
|
|
162
|
+
def rates(dimension = nil)
|
|
163
|
+
unless dimension.blank?
|
|
164
|
+
send("#{dimension}_rates")
|
|
165
|
+
else
|
|
166
|
+
rates_without_dimension
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Returns the name of the cache column for the passed dimension.
|
|
171
|
+
def caching_column_name(dimension = nil)
|
|
172
|
+
self.class.caching_column_name(dimension)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Updates the cached average column in the rateable model.
|
|
176
|
+
def update_cached_average(dimension = nil)
|
|
177
|
+
if self.class.caching_average?(dimension)
|
|
178
|
+
update_attribute caching_column_name(dimension), self.rate_average(false, dimension)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
module SingletonMethods
|
|
184
|
+
|
|
185
|
+
# Maximum value accepted when rating the model. Default is 5.
|
|
186
|
+
#
|
|
187
|
+
# Change it by passing the :stars option to +ajaxful_rateable+
|
|
188
|
+
#
|
|
189
|
+
# ajaxful_rateable :stars => 10
|
|
190
|
+
def max_stars
|
|
191
|
+
axr_config[:stars]
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Name of the class for the user model.
|
|
195
|
+
def user_class_name
|
|
196
|
+
Rate.reflect_on_association(:rater).options[:class_name]
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Gets the user's class
|
|
200
|
+
def user_class
|
|
201
|
+
user_class_name.constantize
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Finds all rateable objects rated by the +user+.
|
|
205
|
+
def find_rated_by(user, dimension = nil)
|
|
206
|
+
find_statement(:rater_id, user.id, dimension)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Finds all rateable objects rated with +stars+.
|
|
210
|
+
def find_rated_with(stars, dimension = nil)
|
|
211
|
+
find_statement(:stars, stars, dimension)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Finds the rateable object with the highest rate average.
|
|
215
|
+
def find_most_popular(dimension = nil)
|
|
216
|
+
all.sort_by { |o| o.rate_average(true, dimension) }.last
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Finds the rateable object with the lowest rate average.
|
|
220
|
+
def find_less_popular(dimension = nil)
|
|
221
|
+
all.sort_by { |o| o.rate_average(true, dimension) }.first
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Finds rateable objects by Rate's attribute.
|
|
225
|
+
def find_statement(attr_name, attr_value, dimension = nil)
|
|
226
|
+
sql = "SELECT DISTINCT r2.* FROM rates r1 INNER JOIN "\
|
|
227
|
+
"#{self.base_class.table_name} r2 ON r1.rateable_id = r2.id WHERE "
|
|
228
|
+
|
|
229
|
+
sql << sanitize_sql_for_conditions({
|
|
230
|
+
:rateable_type => self.base_class.name,
|
|
231
|
+
attr_name => attr_value,
|
|
232
|
+
:dimension => (dimension.to_s if dimension)
|
|
233
|
+
}, 'r1')
|
|
234
|
+
|
|
235
|
+
find_by_sql(sql)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Indicates if the rateable model is able to cache the rate average.
|
|
239
|
+
#
|
|
240
|
+
# Include a column named +rating_average+ in your rateable model with
|
|
241
|
+
# default null, as decimal:
|
|
242
|
+
#
|
|
243
|
+
# t.decimal :rating_average, :precision => 3, :scale => 1, :default => 0
|
|
244
|
+
#
|
|
245
|
+
# To customize the name of the column specify the option <tt>:cache_column</tt> to ajaxful_rateable
|
|
246
|
+
#
|
|
247
|
+
# ajaxful_rateable :cache_column => :my_custom_column
|
|
248
|
+
#
|
|
249
|
+
def caching_average?(dimension = nil)
|
|
250
|
+
column_names.include?(caching_column_name(dimension))
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Returns the name of the cache column for the passed dimension.
|
|
254
|
+
def caching_column_name(dimension = nil)
|
|
255
|
+
name = axr_config[:cache_column].to_s
|
|
256
|
+
name += "_#{dimension.to_s.underscore}" unless dimension.blank?
|
|
257
|
+
name
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
class ActiveRecord::Base
|
|
263
|
+
include AjaxfulRating
|
|
264
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module AjaxfulRating # :nodoc:
|
|
2
|
+
class StarsBuilder # :nodoc:
|
|
3
|
+
include AjaxfulRating::Locale
|
|
4
|
+
|
|
5
|
+
attr_reader :rateable, :user, :options
|
|
6
|
+
|
|
7
|
+
def initialize(rateable, user_or_static, template, css_builder, options = {})
|
|
8
|
+
@user = user_or_static unless user_or_static == :static
|
|
9
|
+
@rateable, @template, @css_builder = rateable, template, css_builder
|
|
10
|
+
apply_stars_builder_options!(options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def show_value
|
|
14
|
+
if options[:show_user_rating]
|
|
15
|
+
rate = rateable.rate_by(user, options[:dimension]) if user
|
|
16
|
+
rate ? rate.stars : 0
|
|
17
|
+
else
|
|
18
|
+
rateable.rate_average(true, options[:dimension])
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def render
|
|
23
|
+
options[:wrap] ? wrapper_tag : ratings_tag
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def apply_stars_builder_options!(options)
|
|
29
|
+
@options = {
|
|
30
|
+
:url => nil,
|
|
31
|
+
:method => :post,
|
|
32
|
+
:wrap => true,
|
|
33
|
+
:size => nil,
|
|
34
|
+
:show_user_rating => false,
|
|
35
|
+
:force_static => false,
|
|
36
|
+
:current_user => (@template.current_user if @template.respond_to?(:current_user))
|
|
37
|
+
}.merge(options)
|
|
38
|
+
|
|
39
|
+
@options[:show_user_rating] = @options[:show_user_rating].to_s == 'true'
|
|
40
|
+
@options[:wrap] = @options[:wrap].to_s == 'true'
|
|
41
|
+
|
|
42
|
+
if @options[:url].nil?
|
|
43
|
+
rateable_name = ActionController::RecordIdentifier.singular_class_name(rateable)
|
|
44
|
+
url = "rate_#{rateable_name}_path"
|
|
45
|
+
if @template.respond_to?(url)
|
|
46
|
+
@options[:url] = @template.send(url, rateable)
|
|
47
|
+
else
|
|
48
|
+
raise(MissingRateRoute)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def ratings_tag
|
|
54
|
+
stars = []
|
|
55
|
+
width = (show_value / rateable.class.max_stars.to_f) * 100
|
|
56
|
+
li_class = "axr-#{show_value}-#{rateable.class.max_stars}".gsub('.', '_')
|
|
57
|
+
@css_builder.rule('.ajaxful-rating', :width => (rateable.class.max_stars * 25))
|
|
58
|
+
@css_builder.rule('.ajaxful-rating.medium',
|
|
59
|
+
:width => (rateable.class.max_stars * 18)) if options[:size] == 'medium'
|
|
60
|
+
@css_builder.rule('.ajaxful-rating.small',
|
|
61
|
+
:width => (rateable.class.max_stars * 10)) if options[:size] == 'small'
|
|
62
|
+
|
|
63
|
+
stars << @template.content_tag(:li, i18n(:current), :class => "show-value",
|
|
64
|
+
:style => "width: #{width}%")
|
|
65
|
+
stars += (1..rateable.class.max_stars).map do |i|
|
|
66
|
+
star_tag(i)
|
|
67
|
+
end
|
|
68
|
+
if options[:size] == 'small'
|
|
69
|
+
size = ' small'
|
|
70
|
+
elsif options[:size] == 'medium'
|
|
71
|
+
size = ' medium'
|
|
72
|
+
end
|
|
73
|
+
# When using rails_xss plugin, it needs to render as HTML
|
|
74
|
+
@template.content_tag(:ul, stars.join.try(:html_safe), :class => "ajaxful-rating#{size}")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def star_tag(value)
|
|
78
|
+
already_rated = rateable.rated_by?(user, options[:dimension]) if user
|
|
79
|
+
css_class = "stars-#{value}"
|
|
80
|
+
@css_builder.rule(".ajaxful-rating .#{css_class}", {
|
|
81
|
+
:width => "#{(value / rateable.class.max_stars.to_f) * 100}%",
|
|
82
|
+
:zIndex => (rateable.class.max_stars + 2 - value).to_s
|
|
83
|
+
})
|
|
84
|
+
@template.content_tag(:li) do
|
|
85
|
+
if !options[:force_static] && (user && options[:current_user] == user &&
|
|
86
|
+
(!already_rated || rateable.axr_config[:allow_update]))
|
|
87
|
+
link_star_tag(value, css_class)
|
|
88
|
+
else
|
|
89
|
+
@template.content_tag(:span, show_value, :class => css_class, :title => i18n(:current))
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def link_star_tag(value, css_class)
|
|
95
|
+
html = {
|
|
96
|
+
:"data-method" => options[:method],
|
|
97
|
+
:"data-stars" => value,
|
|
98
|
+
:"data-dimension" => options[:dimension],
|
|
99
|
+
:"data-size" => options[:size],
|
|
100
|
+
:"data-show_user_rating" => options[:show_user_rating],
|
|
101
|
+
:class => css_class,
|
|
102
|
+
:title => i18n(:hover, value)
|
|
103
|
+
}
|
|
104
|
+
@template.link_to(value, options[:url], html)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def wrapper_tag
|
|
108
|
+
@template.content_tag(:div, ratings_tag, :class => "ajaxful-rating-wrapper",
|
|
109
|
+
:id => rateable.wrapper_dom_id(options))
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ajaxful_rating_jquery
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 21
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 2
|
|
8
|
+
- 2
|
|
9
|
+
- 9
|
|
10
|
+
version: 2.2.9
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Jack Chu, Edgar J. Suarez
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-09-30 00:00:00 -04:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies: []
|
|
21
|
+
|
|
22
|
+
description: Provides a simple way to add rating functionality to your application. This is a fork of ajaxful_ratings that works with jQuery instead of Prototype and uses unobtrusive javascript instead of link_to_remote.
|
|
23
|
+
email: kamuigt@gmail.com
|
|
24
|
+
executables: []
|
|
25
|
+
|
|
26
|
+
extensions: []
|
|
27
|
+
|
|
28
|
+
extra_rdoc_files:
|
|
29
|
+
- CHANGELOG
|
|
30
|
+
- README.textile
|
|
31
|
+
- lib/ajaxful_rating_jquery.rb
|
|
32
|
+
- lib/axr/css_builder.rb
|
|
33
|
+
- lib/axr/errors.rb
|
|
34
|
+
- lib/axr/helpers.rb
|
|
35
|
+
- lib/axr/locale.rb
|
|
36
|
+
- lib/axr/model.rb
|
|
37
|
+
- lib/axr/stars_builder.rb
|
|
38
|
+
files:
|
|
39
|
+
- CHANGELOG
|
|
40
|
+
- Manifest
|
|
41
|
+
- README.textile
|
|
42
|
+
- Rakefile
|
|
43
|
+
- generators/ajaxful_rating/USAGE
|
|
44
|
+
- generators/ajaxful_rating/ajaxful_rating_generator.rb
|
|
45
|
+
- generators/ajaxful_rating/templates/images/star.png
|
|
46
|
+
- generators/ajaxful_rating/templates/images/star_medium.png
|
|
47
|
+
- generators/ajaxful_rating/templates/images/star_small.png
|
|
48
|
+
- generators/ajaxful_rating/templates/migration.rb
|
|
49
|
+
- generators/ajaxful_rating/templates/model.rb
|
|
50
|
+
- generators/ajaxful_rating/templates/style.css
|
|
51
|
+
- init.rb
|
|
52
|
+
- lib/ajaxful_rating_jquery.rb
|
|
53
|
+
- lib/axr/css_builder.rb
|
|
54
|
+
- lib/axr/errors.rb
|
|
55
|
+
- lib/axr/helpers.rb
|
|
56
|
+
- lib/axr/locale.rb
|
|
57
|
+
- lib/axr/model.rb
|
|
58
|
+
- lib/axr/stars_builder.rb
|
|
59
|
+
- ajaxful_rating_jquery.gemspec
|
|
60
|
+
has_rdoc: true
|
|
61
|
+
homepage: http://github.com/kamui/ajaxful_rating_jquery
|
|
62
|
+
licenses: []
|
|
63
|
+
|
|
64
|
+
post_install_message:
|
|
65
|
+
rdoc_options:
|
|
66
|
+
- --line-numbers
|
|
67
|
+
- --inline-source
|
|
68
|
+
- --title
|
|
69
|
+
- Ajaxful_rating_jquery
|
|
70
|
+
- --main
|
|
71
|
+
- README.textile
|
|
72
|
+
require_paths:
|
|
73
|
+
- lib
|
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
|
+
none: false
|
|
76
|
+
requirements:
|
|
77
|
+
- - ">="
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
hash: 3
|
|
80
|
+
segments:
|
|
81
|
+
- 0
|
|
82
|
+
version: "0"
|
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
|
+
none: false
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
hash: 11
|
|
89
|
+
segments:
|
|
90
|
+
- 1
|
|
91
|
+
- 2
|
|
92
|
+
version: "1.2"
|
|
93
|
+
requirements: []
|
|
94
|
+
|
|
95
|
+
rubyforge_project: ajaxful_rating_jquery
|
|
96
|
+
rubygems_version: 1.3.7
|
|
97
|
+
signing_key:
|
|
98
|
+
specification_version: 3
|
|
99
|
+
summary: Add star rating functionality to your Rails 2.3.x application. Requires jQuery.
|
|
100
|
+
test_files: []
|
|
101
|
+
|