rateable 0.0.7 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/Gemfile +5 -0
- data/README.rdoc +1 -1
- data/Rakefile +14 -0
- data/lib/rateable/helper.rb +3 -2
- data/lib/rateable/is_rateable.rb +18 -3
- data/lib/rateable/rate.rb +7 -1
- data/lib/rateable/rater.rb +1 -1
- data/lib/rateable/version.rb +1 -1
- data/rateable.gemspec +6 -0
- data/spec/controllers/application_controller_spec.rb +48 -0
- data/spec/controllers/pictures_controller_spec.rb +57 -0
- data/spec/factories.rb +8 -0
- data/spec/models/rateable_spec.rb +70 -0
- data/spec/models/rater_spec.rb +32 -0
- data/spec/requests/pictures_spec.rb +66 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/test_app/.gitignore +4 -0
- data/spec/test_app/.rspec +1 -0
- data/spec/test_app/Gemfile +37 -0
- data/spec/test_app/README +256 -0
- data/spec/test_app/Rakefile +7 -0
- data/spec/test_app/app/controllers/application_controller.rb +20 -0
- data/spec/test_app/app/controllers/pictures_controller.rb +19 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/helpers/pictures_helper.rb +2 -0
- data/spec/test_app/app/models/picture.rb +3 -0
- data/spec/test_app/app/models/user.rb +3 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/app/views/pictures/show.html.erb +3 -0
- data/spec/test_app/config.ru +4 -0
- data/spec/test_app/config/app_config.yml +2 -0
- data/spec/test_app/config/application.rb +42 -0
- data/spec/test_app/config/boot.rb +6 -0
- data/spec/test_app/config/database.yml +22 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +26 -0
- data/spec/test_app/config/environments/production.rb +49 -0
- data/spec/test_app/config/environments/test.rb +35 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/inflections.rb +10 -0
- data/spec/test_app/config/initializers/mime_types.rb +5 -0
- data/spec/test_app/config/initializers/secret_token.rb +7 -0
- data/spec/test_app/config/initializers/session_store.rb +8 -0
- data/spec/test_app/config/locales/en.yml +5 -0
- data/spec/test_app/config/routes.rb +69 -0
- data/spec/test_app/db/migrate/20110806140922_create_users.rb +13 -0
- data/spec/test_app/db/migrate/20110806140953_create_pictures.rb +13 -0
- data/spec/test_app/db/migrate/20110806141552_rateable_migration.rb +15 -0
- data/spec/test_app/db/schema.rb +35 -0
- data/spec/test_app/db/seeds.rb +7 -0
- data/spec/test_app/doc/README_FOR_APP +2 -0
- data/spec/test_app/public/404.html +26 -0
- data/spec/test_app/public/422.html +26 -0
- data/spec/test_app/public/500.html +26 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/test_app/public/images/rails.png +0 -0
- data/spec/test_app/public/images/rateable/star_filled.png +0 -0
- data/spec/test_app/public/images/rateable/star_unfilled.png +0 -0
- data/spec/test_app/public/javascripts/application.js +2 -0
- data/spec/test_app/public/javascripts/controls.js +965 -0
- data/spec/test_app/public/javascripts/dragdrop.js +974 -0
- data/spec/test_app/public/javascripts/effects.js +1123 -0
- data/spec/test_app/public/javascripts/jquery.js +8374 -0
- data/spec/test_app/public/javascripts/prototype.js +6001 -0
- data/spec/test_app/public/javascripts/rails.js +196 -0
- data/spec/test_app/public/javascripts/rateable.js +29 -0
- data/spec/test_app/public/robots.txt +5 -0
- data/spec/test_app/public/stylesheets/rateable.css +22 -0
- data/spec/test_app/script/rails +6 -0
- data/spec/test_app/spec/helpers/application_spec.rb +48 -0
- data/spec/test_app/spec/spec_helper.rb +42 -0
- metadata +154 -4
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -1,2 +1,16 @@
|
|
1
1
|
require 'bundler'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
2
5
|
Bundler::GemHelper.install_tasks
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
8
|
+
t.rspec_opts = ['--options', "spec/spec.opts"]
|
9
|
+
t.pattern = "spec/**/*_spec.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new(:spec_rcov) do |t|
|
13
|
+
t.rspec_opts = ['--options', "spec/spec.opts"]
|
14
|
+
t.pattern = "spec/**/*_spec.rb"
|
15
|
+
t.rcov = true
|
16
|
+
end
|
data/lib/rateable/helper.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Rateable
|
2
2
|
module Helper
|
3
3
|
def rating_for(rateable, args = {})
|
4
|
-
|
4
|
+
raise "The given model of class #{rateable.class} is not rateable" if rateable.nil? or not (rateable.respond_to?(:is_rateable?) and rateable.is_rateable?)
|
5
|
+
user = args[:user] || begin try(:current_user) rescue nil end
|
5
6
|
if user and user.ratings.where(:rateable => rateable).empty?
|
6
|
-
render :partial => "rateable/rate", :locals => {:url => args[:url] ? args[:url] : url_for(rateable), :stars => args[:stars]}
|
7
|
+
render :partial => "rateable/rate", :locals => {:url => args[:url] ? args[:url] : url_for([:rate, rateable]), :stars => args[:stars]}
|
7
8
|
else
|
8
9
|
stars_average = rateable.ratings.average("stars")
|
9
10
|
ratings_count = rateable.ratings.count
|
data/lib/rateable/is_rateable.rb
CHANGED
@@ -5,7 +5,9 @@ module Rateable
|
|
5
5
|
end
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
def is_rateable
|
8
|
+
def is_rateable(args = {})
|
9
|
+
raise ":stars must be an integer >= 1" if args[:stars] and not (args[:stars].is_a?(Integer) and args[:stars] >= 1)
|
10
|
+
@max_stars = args[:stars] || 5
|
9
11
|
has_many :ratings, :as => :rateable, :class_name => "Rateable::Rate", :dependent => :destroy
|
10
12
|
include Rateable::IsRateable::InstanceMethods
|
11
13
|
end
|
@@ -13,6 +15,11 @@ module Rateable
|
|
13
15
|
def is_rateable?
|
14
16
|
true
|
15
17
|
end
|
18
|
+
|
19
|
+
def max_stars
|
20
|
+
@max_stars
|
21
|
+
end
|
22
|
+
|
16
23
|
end
|
17
24
|
|
18
25
|
module InstanceMethods
|
@@ -20,11 +27,19 @@ module Rateable
|
|
20
27
|
true
|
21
28
|
end
|
22
29
|
|
30
|
+
def max_stars
|
31
|
+
self.class.max_stars
|
32
|
+
end
|
33
|
+
|
23
34
|
# include instance methods that are needed
|
24
35
|
def rate(user,stars)
|
36
|
+
raise "#{user.inspect} is not a rater" unless user.respond_to?(:is_rater?) and user.is_rater?
|
25
37
|
rating = Rate.where(:rateable => self, :rater => user).first
|
26
|
-
|
27
|
-
|
38
|
+
unless rating
|
39
|
+
rating = Rate.create(:rateable => self, :rater => user, :stars => stars)
|
40
|
+
else
|
41
|
+
rating.stars = stars
|
42
|
+
end
|
28
43
|
rating.save
|
29
44
|
end
|
30
45
|
end
|
data/lib/rateable/rate.rb
CHANGED
@@ -5,6 +5,12 @@ module Rateable
|
|
5
5
|
|
6
6
|
validates_presence_of :rateable
|
7
7
|
validates_presence_of :rater
|
8
|
-
|
8
|
+
validate :stars_must_be_in_range
|
9
|
+
|
10
|
+
def stars_must_be_in_range
|
11
|
+
unless (1..rateable.max_stars).include? stars
|
12
|
+
errors.add :stars, "must be within 1 to #{rateable.max_stars}"
|
13
|
+
end
|
14
|
+
end
|
9
15
|
end
|
10
16
|
end
|
data/lib/rateable/rater.rb
CHANGED
data/lib/rateable/version.rb
CHANGED
data/rateable.gemspec
CHANGED
@@ -14,6 +14,12 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
s.add_runtime_dependency 'rails', ">= 3.0.0"
|
16
16
|
s.add_runtime_dependency 'activerecord', ">= 3.0.0"
|
17
|
+
s.add_runtime_dependency 'meta_where'
|
18
|
+
s.add_development_dependency "rspec"
|
19
|
+
s.add_development_dependency "capybara"
|
20
|
+
s.add_development_dependency "rspec-rails"
|
21
|
+
s.add_development_dependency "factory_girl_rails"
|
22
|
+
s.add_development_dependency "factory_girl"
|
17
23
|
|
18
24
|
s.files = `git ls-files`.split("\n")
|
19
25
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ApplicationController do
|
4
|
+
let(:user){ Factory(:user) }
|
5
|
+
|
6
|
+
describe :login do
|
7
|
+
it "it saves the given user_id in the session" do
|
8
|
+
get :login, :user_id => user.id
|
9
|
+
session[:user_id].should == user.id
|
10
|
+
end
|
11
|
+
|
12
|
+
it "saves nil in the session if no id is given" do
|
13
|
+
get :login
|
14
|
+
session[:user_id].should == nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe :logout do
|
19
|
+
it "sets the user in the session to nil if user is logged in" do
|
20
|
+
session[:user_id] = user.id
|
21
|
+
get :logout
|
22
|
+
session[:user_id].should == nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sets the user in the session to nil if no user logged in" do
|
26
|
+
get :logout
|
27
|
+
session[:user_id].should == nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe :current_user do
|
32
|
+
it "returns nil if session[:user_id] is nil and no user_id is given as param" do
|
33
|
+
session[:user_id] = nil
|
34
|
+
controller.current_user.should == nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "return user if session nil and user_id is given as param" do
|
38
|
+
session[:user_id] = nil
|
39
|
+
get :logout, :user_id => user.id
|
40
|
+
controller.current_user.should == user
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns the User with session[:user_id] as it's id" do
|
44
|
+
session[:user_id] = user.id
|
45
|
+
controller.current_user.should == user
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PicturesController, "rating a picture" do
|
4
|
+
|
5
|
+
it "should rate the picture" do
|
6
|
+
picture = Factory(:picture)
|
7
|
+
user = Factory(:user)
|
8
|
+
post 'rate', :user_id => user.id, :id => picture.id, :stars => 1
|
9
|
+
ratings = user.reload.ratings
|
10
|
+
ratings.count.should == 1
|
11
|
+
ratings.first.rateable.should == picture
|
12
|
+
ratings.first.stars.should == 1
|
13
|
+
response.should be_success
|
14
|
+
end
|
15
|
+
|
16
|
+
it "is not possible unless logged in" do
|
17
|
+
picture = Factory(:picture)
|
18
|
+
post 'rate', :id => picture.id, :stars => 1
|
19
|
+
picture.ratings.count.should == 0
|
20
|
+
response.should_not be_success
|
21
|
+
response.body.should == "You are not allowed to vote for this item!"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "is not possible if already voted" do
|
25
|
+
picture = Factory(:picture)
|
26
|
+
user = Factory(:user)
|
27
|
+
user.rate(picture, 1)
|
28
|
+
post 'rate', :id => picture.id, :user_id => user.id, :stars => 1
|
29
|
+
response.should_not be_success
|
30
|
+
picture.ratings.count.should == 1
|
31
|
+
end
|
32
|
+
|
33
|
+
it "is not possible to vote if no stars are given" do
|
34
|
+
picture = Factory(:picture)
|
35
|
+
user = Factory(:user)
|
36
|
+
post 'rate', :id => picture.id, :user_id => user.id
|
37
|
+
response.should_not be_success
|
38
|
+
picture.ratings.count.should == 0
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should not be possible with to many stars" do
|
42
|
+
picture = Factory(:picture)
|
43
|
+
user = Factory(:user)
|
44
|
+
post 'rate', :id => picture.id, :user_id => user.id, :stars => picture.max_stars+1
|
45
|
+
response.should_not be_success
|
46
|
+
picture.ratings.count.should == 0
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not be possible with to less stars" do
|
50
|
+
picture = Factory(:picture)
|
51
|
+
user = Factory(:user)
|
52
|
+
post 'rate', :id => picture.id, :user_id => user.id, :stars => 0
|
53
|
+
response.should_not be_success
|
54
|
+
picture.ratings.count.should == 0
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/spec/factories.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Picture do
|
4
|
+
|
5
|
+
it "should have many ratings" do
|
6
|
+
Factory(:picture).should respond_to(:ratings)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe :is_rateable? do
|
10
|
+
it "as instance method returns true" do
|
11
|
+
picture = Factory(:picture)
|
12
|
+
assert picture.is_rateable?
|
13
|
+
end
|
14
|
+
|
15
|
+
it "as class method returns true" do
|
16
|
+
assert Picture.is_rateable?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe :rate do
|
21
|
+
let(:picture) { Factory(:picture) }
|
22
|
+
let(:user) { Factory(:user) }
|
23
|
+
|
24
|
+
it "raises an exception if no valid rater is given" do
|
25
|
+
lambda{picture.rate(picture,1)}.should raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
it "changes the rating of the given rater if already voted and stars are valid" do
|
29
|
+
rating = Rateable::Rate.create(:rateable => picture, :rater => user, :stars => 1)
|
30
|
+
picture.rate(user,2).should == true
|
31
|
+
rating.id.should == picture.ratings.last.id
|
32
|
+
picture.ratings.last.stars.should == 2
|
33
|
+
end
|
34
|
+
|
35
|
+
it "does not change the rating of the given rater if already voted and stars are not valid" do
|
36
|
+
Rateable::Rate.create(:rateable => picture, :rater => user, :stars => 1)
|
37
|
+
picture.rate(user,0).should == false
|
38
|
+
picture.ratings.last.stars.should == 1
|
39
|
+
picture.rate(user,100000).should == false
|
40
|
+
picture.ratings.last.stars.should == 1
|
41
|
+
end
|
42
|
+
|
43
|
+
it "creates a new rating if valid rater and stars are given and not already rated" do
|
44
|
+
user.ratings.empty?.should be_true
|
45
|
+
picture.rate(user,1).should be_true
|
46
|
+
rating = picture.ratings.last
|
47
|
+
rating.rater.should == user
|
48
|
+
rating.rateable.should == picture
|
49
|
+
rating.stars.should == 1
|
50
|
+
end
|
51
|
+
|
52
|
+
it "does not create a new rating if valid rater and invalid stars are given" do
|
53
|
+
picture.rate(user,0).should be_false
|
54
|
+
picture.ratings.last.should be_nil
|
55
|
+
picture.rate(user,10000).should be_false
|
56
|
+
picture.ratings.last.should be_nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe :max_stars do
|
61
|
+
it "returns the value of the class-method max_stars" do
|
62
|
+
Factory(:picture).max_stars.should == Picture.max_stars
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns an integer" do
|
66
|
+
Picture.max_stars.should be_an(Integer)
|
67
|
+
Picture.max_stars.should >= 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe User do
|
4
|
+
describe :is_rater? do
|
5
|
+
it "as instance method returns true" do
|
6
|
+
user = Factory(:user)
|
7
|
+
assert user.is_rater?
|
8
|
+
end
|
9
|
+
|
10
|
+
it "as class method returns true" do
|
11
|
+
assert User.is_rater?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe :rate do
|
16
|
+
let(:user) { Factory(:user) }
|
17
|
+
|
18
|
+
it "should call Rateable.rate if object is rateable" do
|
19
|
+
picture = Factory(:picture)
|
20
|
+
picture.should_receive(:rate).with(user,1)
|
21
|
+
user.rate(picture,1)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns false if the object does not respond to is_rateable?" do
|
25
|
+
user.rate(user,1).should == false
|
26
|
+
end
|
27
|
+
|
28
|
+
it "returns false if the object is nil" do
|
29
|
+
user.rate(nil,1).should == false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Pictures" do
|
4
|
+
it "shows the picture when visiting the show action" do
|
5
|
+
picture = Factory(:picture)
|
6
|
+
visit picture_path(picture)
|
7
|
+
page.should have_content(picture.name)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should not set current_user when no user_id is given" do
|
11
|
+
user = Factory(:user)
|
12
|
+
picture = Factory(:picture)
|
13
|
+
visit picture_path(picture)
|
14
|
+
User.all.each do |u|
|
15
|
+
page.should_not have_content(u.email)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set current_user when a user_id is given" do
|
20
|
+
picture = Factory(:picture)
|
21
|
+
user = Factory(:user)
|
22
|
+
visit picture_path(picture, :user_id => user.id)
|
23
|
+
page.should have_content(user.email)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should show star images when not logged in" do
|
27
|
+
picture = Factory(:picture)
|
28
|
+
visit picture_path(picture)
|
29
|
+
page.should_not have_xpath('//div[@class="rating"]/a')
|
30
|
+
page.should have_xpath('//div[@class="rating"]/img')
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should show a star links when logged in and not already voted" do
|
34
|
+
picture = Factory(:picture)
|
35
|
+
user = Factory(:user)
|
36
|
+
user.ratings.destroy_all
|
37
|
+
visit picture_path(picture, :user_id => user.id)
|
38
|
+
page.should have_xpath('//div[@class="rating"]/a[@class="rate"]')
|
39
|
+
page.should_not have_xpath('//div[@class="rating"]/img')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "shows star images when logged in and already voted" do
|
43
|
+
picture = Factory(:picture)
|
44
|
+
user = Factory(:user)
|
45
|
+
user.rate(picture,1)
|
46
|
+
visit picture_path(picture, :user_id => user.id)
|
47
|
+
page.should_not have_xpath('//div[@class="rating"]/a[@class="rate"]')
|
48
|
+
page.should have_xpath('//div[@class="rating"]/img')
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should be possible to vote", :js => true do
|
52
|
+
picture = Factory(:picture)
|
53
|
+
user = Factory(:user)
|
54
|
+
user.ratings.destroy_all
|
55
|
+
visit login_path(:user_id => user.id)
|
56
|
+
visit picture_path(picture)
|
57
|
+
page.should have_xpath('//div[@class="rating"]/a[@class="rate"]')
|
58
|
+
find(:xpath, '//div[@class="rating"]/a[@class="rate"][3]').click
|
59
|
+
page.should have_no_xpath('//div[@class="rating"]/a[@class="rate"]')
|
60
|
+
page.should have_xpath('//div[@class="rating"]/img[@alt="Star_filled"][1]')
|
61
|
+
page.should have_xpath('//div[@class="rating"]/img[@alt="Star_filled"][2]')
|
62
|
+
page.should have_xpath('//div[@class="rating"]/img[@alt="Star_filled"][3]')
|
63
|
+
page.should have_no_xpath('//div[@class="rating"]/img[@alt="Star_filled"][4]')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
data/spec/spec.opts
ADDED