acts_as_rateable 2.0.1

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.
@@ -0,0 +1,11 @@
1
+ == 2.0 released 2009-7-22
2
+
3
+ * Refactored database structure for better performance: the average rating and ratings count are now pre-computed and updated when new ratings are recorded
4
+ * The API now requires consistently the user object instead of the user_id
5
+ * Added testing framework and unit tests
6
+ * Made available as ruby gem
7
+
8
+ == 1.0 released 2008
9
+
10
+ * The original acts_as_rateable plugin, first release by Ferenc Fekete
11
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 [name of plugin creator]
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.
@@ -0,0 +1,77 @@
1
+ = Acts As Rateble
2
+
3
+ Acts_as_rateable is a rails plugin providing a rating interface for ActiveRecord models.
4
+ It is released under the MIT license.
5
+ The original plugin is used on cotcot.hu for article rating, sponsored quizzes, etc.
6
+
7
+ = Features
8
+
9
+ * Rating scores are recorded by user
10
+ * Users can update previous ratings
11
+ * Uses a polymorphic association to your model, so no changes to your existing models in the database are required
12
+ * Stores computed score and number of ratings for efficient data access
13
+ * Possibility to change range of the ratings (1..5 is default)
14
+
15
+ = Installation
16
+
17
+ == Install as gem (recommended)
18
+
19
+ Install as a gem:
20
+
21
+ $ sudo gem install mreinsch-acts_as_rateable
22
+
23
+ Then add the gem dependency in your config:
24
+
25
+ # config/environment.rb
26
+ config.gem "mreinsch-acts_as_rateable", :source => "http://gems.github.com", :lib => "acts_as_rateable"
27
+
28
+ == Install as plugin
29
+
30
+ To install as a plugin, use:
31
+
32
+ $ ./script/plugin install git://github.com/mreinsch/acts_as_rateable.git
33
+
34
+ = Example Usage
35
+
36
+ Install the plugin into your vendor/plugins directory, insert 'acts_as_rateable' into your model, then restart your application.
37
+
38
+ class Post < ActiveRecord::Base
39
+ acts_as_rateable
40
+ end
41
+
42
+ Now your model is extended by the plugin, you can rate it (1-#) or calculate the average rating.
43
+
44
+ @post.rate_it(4, current_user)
45
+
46
+ @post.average_rating #=> 4.0
47
+ @post.average_rating_round #=> 4
48
+ @post.average_rating_percent #=> 80
49
+ @post.rated_by?(current_user) #=> true
50
+ @post.rating_by(current_user) #=> 4
51
+ @post.ratings_couunt #=> 1
52
+
53
+ Post.find_top_rated #=> top rated records
54
+
55
+ Optional you can specify the highest score using the :max_rating paramter as follows. The default for :max_rating is 5.
56
+
57
+ class Comment < ActiveRecord::Base
58
+ acts_as_rateable :max_rating => 10
59
+ end
60
+
61
+ See acts_as_rateable.rb for further details!
62
+
63
+ = Updating
64
+
65
+ == Updating from Ferenc Fekete's acts_as_rateable v1.0
66
+
67
+ 1. Remove the old plugin, and install this version.
68
+ 1. Check your code and make sure you pass the user object instead of the user ID for the rate_it, rated_by? and rating_by methods.
69
+ 1. Generate an update migration using: ./script/generate acts_as_rateable_update1
70
+ 1. Run your test cases
71
+
72
+
73
+ = Copyright
74
+
75
+ Copyright (c) 2007 Ferenc Fekete, http://xpnindustries.com , released under the MIT license
76
+
77
+ Copyright (c) 2009 mobalean LLC, http://www.mobalean.com
@@ -0,0 +1,22 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the acts_as_ratable plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the acts_as_ratable plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'ActsAsRatable'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
@@ -0,0 +1,7 @@
1
+ class ActsAsRateableMigrationGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => "acts_as_rateable_migration"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,24 @@
1
+ class ActsAsRateableMigration < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "ratings" do |t|
4
+ t.references "rateable", :polymorphic => true, :nil => false
5
+ t.float "average_rating"
6
+ t.integer "ratings_count"
7
+ t.timestamps
8
+ end
9
+ add_index "ratings", ["rateable_id", "rateable_type"]
10
+
11
+ create_table "user_ratings" do |t|
12
+ t.references "rating", :nil => false
13
+ t.references "user", :nil => false
14
+ t.integer "score", :nil => false
15
+ t.timestamps
16
+ end
17
+ add_index "user_ratings", ["user_id", "rating_id"]
18
+ end
19
+
20
+ def self.down
21
+ drop_table "user_ratings"
22
+ drop_table "ratings"
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ class ActsAsRateableUpdate1Generator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => "acts_as_rateable_update1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,48 @@
1
+ class ActsAsRateableUpdate1 < ActiveRecord::Migration
2
+ def self.up
3
+ rename_table "rates", "old_rates"
4
+ rename_table "ratings", "old_ratings"
5
+
6
+ create_table "ratings" do |t|
7
+ t.references "rateable", :polymorphic => true, :nil => false
8
+ t.float "average_rating"
9
+ t.integer "ratings_count"
10
+ t.timestamps
11
+ end
12
+ add_index "ratings", ["rateable_id", "rateable_type"]
13
+
14
+ create_table "user_ratings" do |t|
15
+ t.references "rating", :nil => false
16
+ t.references "user", :nil => false
17
+ t.integer "score", :nil => false
18
+ t.timestamps
19
+ end
20
+ add_index "user_ratings", ["user_id", "rating_id"]
21
+
22
+ say_with_time "migrating exsting ratings" do
23
+ connection.transaction do
24
+ sql = "SELECT rateable_id, rateable_type, user_id, score, old_ratings.created_at, old_ratings.updated_at " +
25
+ "FROM old_ratings INNER JOIN old_rates ON old_ratings.rate_id = old_rates.id"
26
+ connection.select_all(sql).each do |row|
27
+ rating = Rating.find_or_create_by_rateable_id_and_rateable_type(
28
+ :rateable_id => row['rateable_id'],
29
+ :rateable_type => row['rateable_type'],
30
+ :created_at => row['created_at'])
31
+ rating.user_ratings.find_or_create_by_user_id(
32
+ :user_id => row['user_id'],
33
+ :score => row['score'],
34
+ :created_at => row['created_at'],
35
+ :updated_at => row['updated_at'])
36
+ end
37
+ Rating.find(:all).each {|rating| rating.update_rating }
38
+ end
39
+ end
40
+
41
+ drop_table "old_rates"
42
+ drop_table "old_ratings"
43
+ end
44
+
45
+ def self.down
46
+ raise ActiveRecord::IrreversibleMigration, "Can't recover old ratings tables"
47
+ end
48
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
@@ -0,0 +1,80 @@
1
+ module ActiveRecord
2
+ module Acts
3
+ module Rateable
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def acts_as_rateable(options = {})
10
+ has_one :rating, :as => :rateable, :dependent => :destroy
11
+
12
+ unless respond_to?(:max_rating)
13
+ class_inheritable_accessor :max_rating
14
+ attr_protected :max_rating
15
+ self.max_rating = options[:max_rating] || 5
16
+ end
17
+
18
+ include ActiveRecord::Acts::Rateable::ClassMethods
19
+ include ActiveRecord::Acts::Rateable::InstanceMethods
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+ # Returns the top rated records, ordered by their average rating.
25
+ # You can use the usual finder parameters to narrow down the records
26
+ # to return.
27
+ # The finder limits the number of returned records to 20 by default.
28
+ # Specify :limit to change it.
29
+ def find_top_rated(params = {})
30
+ find_params = params.merge(:include => :rating)
31
+ find_params[:order] = ['ratings.average_rating DESC', find_params.delete(:order)].compact.join(", ")
32
+ find_params[:limit] = 20 unless find_params.key?(:limit)
33
+ find(:all, find_params)
34
+ end
35
+ end
36
+
37
+ module InstanceMethods
38
+ # Rates the object by a given score. A user object should be passed to the method.
39
+ def rate_it(score, user)
40
+ create_rating unless rating
41
+ rating.rate(score, user)
42
+ end
43
+
44
+ # Returns the average rating. Calculation based on the already given scores.
45
+ def average_rating
46
+ rating && rating.average_rating || 0.0
47
+ end
48
+
49
+ # Rounds the average rating value.
50
+ def average_rating_round
51
+ average_rating.round
52
+ end
53
+
54
+ # Returns the average rating in percent.
55
+ def average_rating_percent
56
+ f = 100 / max_rating.to_f
57
+ average_rating * f
58
+ end
59
+
60
+ # Returns the number of ratings.
61
+ def ratings_count
62
+ rating && rating.ratings_count || 0
63
+ end
64
+
65
+ # Checks whether a user rated the object or not.
66
+ def rated_by?(user)
67
+ rating && rating.user_ratings.exists?(:user_id => user)
68
+ end
69
+
70
+ # Returns the rating a specific user has given the object.
71
+ def rating_by(user)
72
+ user_rating = rating && rating.user_ratings.find_by_user_id(user.id)
73
+ user_rating ? user_rating.score : nil
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,21 @@
1
+ class Rating < ActiveRecord::Base
2
+ belongs_to :rateable, :polymorphic => true
3
+ has_many :user_ratings
4
+
5
+ delegate :max_rating, :to => :rateable
6
+
7
+ def rate(score, user)
8
+ user_ratings.find_or_initialize_by_user_id(user.id).update_attributes!(:score => score)
9
+ reload
10
+ end
11
+
12
+ # Call this method the update the avarage rating; you don't normally need to
13
+ # do this manually, saving or updating a user rating already takes care of
14
+ # updating the avarage rating.
15
+ def update_rating
16
+ self.average_rating = user_ratings.average(:score)
17
+ self.ratings_count = user_ratings.count
18
+ save!
19
+ end
20
+
21
+ end
@@ -0,0 +1,24 @@
1
+ class UserRating < ActiveRecord::Base
2
+ belongs_to :rating
3
+
4
+ delegate :max_rating, :to => :rating
5
+
6
+ validates_presence_of :score
7
+ validates_uniqueness_of :user_id, :scope => :rating_id
8
+ validate :max_rating_allowed_by_parent
9
+
10
+ after_save do |user_rating|
11
+ user_rating.rating.update_rating
12
+ end
13
+
14
+ private
15
+
16
+ def max_rating_allowed_by_parent
17
+ if score < 1
18
+ errors.add(:score, "must be greater than or equal to 1")
19
+ elsif score > max_rating
20
+ errors.add(:score, "must be less than or equal to #{max_rating}")
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,2 @@
1
+ require 'acts_as_rateable'
2
+ ActiveRecord::Base.send(:include, ActiveRecord::Acts::Rateable)
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_rateable
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ferenc Fekete
8
+ - Gabriel Gironda
9
+ - Michael Reinsch
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2009-09-23 00:00:00 +02:00
15
+ default_executable:
16
+ dependencies: []
17
+
18
+ description: Acts_as_rateable is a rails plugin providing a rating interface for ActiveRecord models.
19
+ email: michael@mobalean.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files:
25
+ - README.rdoc
26
+ - CHANGELOG.rdoc
27
+ - MIT-LICENSE
28
+ files:
29
+ - README.rdoc
30
+ - CHANGELOG.rdoc
31
+ - MIT-LICENSE
32
+ - Rakefile
33
+ - init.rb
34
+ - rails/init.rb
35
+ - lib/rating.rb
36
+ - lib/user_rating.rb
37
+ - lib/acts_as_rateable.rb
38
+ - generators/acts_as_rateable_update1/templates/migration.rb
39
+ - generators/acts_as_rateable_update1/acts_as_rateable_update1_generator.rb
40
+ - generators/acts_as_rateable_migration/templates/migration.rb
41
+ - generators/acts_as_rateable_migration/acts_as_rateable_migration_generator.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/mreinsch/acts_as_rateable
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --main
49
+ - README.rdoc
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.5
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Rails plugin providing a rating interface for ActiveRecord models
71
+ test_files: []
72
+