recommendable 0.1.8 → 0.2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +27 -1
- data/Gemfile.lock +18 -10
- data/app/models/recommendable/dislike.rb +4 -0
- data/app/models/recommendable/ignore.rb +6 -3
- data/app/models/recommendable/like.rb +4 -0
- data/app/models/recommendable/{stashed_item.rb → stash.rb} +5 -2
- data/db/migrate/20120127092558_create_ignores.rb +4 -4
- data/db/migrate/20120131173909_create_stashes.rb +17 -0
- data/lib/recommendable.rb +5 -0
- data/lib/recommendable/acts_as_recommendable.rb +20 -9
- data/lib/recommendable/acts_as_recommended_to.rb +60 -26
- data/lib/recommendable/helpers.rb +8 -0
- data/lib/recommendable/version.rb +1 -1
- data/spec/dummy/db/migrate/20120128005555_create_ignores.recommendable.rb +4 -4
- data/spec/dummy/db/migrate/20120131195416_create_stashes.recommendable.rb +19 -0
- data/spec/dummy/db/schema.rb +11 -11
- data/spec/dummy/recommendable_dummy_development +0 -0
- data/spec/dummy/recommendable_dummy_test +0 -0
- data/spec/models/{stashed_item_spec.rb → stash_spec.rb} +3 -3
- metadata +85 -29
- data/db/migrate/20120131173909_create_stashed_items.rb +0 -17
- data/spec/dummy/db/migrate/20120131195416_create_stashed_items.recommendable.rb +0 -18
data/CHANGELOG.markdown
CHANGED
@@ -1,8 +1,34 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
-
0.
|
4
|
+
0.2.0 (current version)
|
5
5
|
-----------------------
|
6
|
+
* NOTE: This release is NOT backwards compatible. Please migrate your databases:
|
7
|
+
|
8
|
+
```
|
9
|
+
rename_column :recommendable_ignores, :ignoreable_id, :ignorable_id
|
10
|
+
rename_column :recommendable_ignores, :ignoreable_type, :ignorable_type
|
11
|
+
rename_table :recommendable_stashed_items, :recommendable_stashes
|
12
|
+
```
|
13
|
+
|
14
|
+
* Fix an issue with recommendable models implemented via STI
|
15
|
+
* Fix a library-wide typo of "ignoreable" to "ignorable"
|
16
|
+
|
17
|
+
0.1.9
|
18
|
+
-----
|
19
|
+
* Yanked due to breaking bug
|
20
|
+
|
21
|
+
0.1.8
|
22
|
+
-----
|
23
|
+
* Revert changes made in 0.1.7 due to licensing
|
24
|
+
|
25
|
+
0.1.7
|
26
|
+
-----
|
27
|
+
* Yanked and no longer available.
|
28
|
+
* Attempted switch from Resque to Sidekiq
|
29
|
+
|
30
|
+
0.1.6
|
31
|
+
-----
|
6
32
|
* Dynamic finders for your User class:
|
7
33
|
|
8
34
|
`current_user.liked_movies`
|
data/Gemfile.lock
CHANGED
@@ -30,8 +30,6 @@ GEM
|
|
30
30
|
multi_json (~> 1.0)
|
31
31
|
arel (3.0.0)
|
32
32
|
builder (3.0.0)
|
33
|
-
celluloid (0.10.0)
|
34
|
-
connection_pool (0.9.1)
|
35
33
|
erubis (2.7.0)
|
36
34
|
hike (1.2.1)
|
37
35
|
i18n (0.6.0)
|
@@ -50,6 +48,8 @@ GEM
|
|
50
48
|
rack (1.4.0)
|
51
49
|
rack-cache (1.1)
|
52
50
|
rack (>= 0.4)
|
51
|
+
rack-protection (1.2.0)
|
52
|
+
rack
|
53
53
|
rack-ssl (1.3.2)
|
54
54
|
rack
|
55
55
|
rack-test (0.6.1)
|
@@ -73,15 +73,20 @@ GEM
|
|
73
73
|
rdoc (3.12)
|
74
74
|
json (~> 1.4)
|
75
75
|
redis (2.2.2)
|
76
|
-
redis-namespace (1.
|
76
|
+
redis-namespace (1.0.3)
|
77
77
|
redis (< 3.0.0)
|
78
|
+
resque (1.19.0)
|
79
|
+
multi_json (~> 1.0)
|
80
|
+
redis-namespace (~> 1.0.2)
|
81
|
+
sinatra (>= 0.9.2)
|
82
|
+
vegas (~> 0.1.2)
|
83
|
+
resque-loner (1.2.0)
|
84
|
+
resque (~> 1.0)
|
78
85
|
shoulda (2.11.3)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
redis
|
84
|
-
redis-namespace
|
86
|
+
sinatra (1.3.2)
|
87
|
+
rack (~> 1.3, >= 1.3.6)
|
88
|
+
rack-protection (~> 1.2)
|
89
|
+
tilt (~> 1.3, >= 1.3.3)
|
85
90
|
sprockets (2.1.2)
|
86
91
|
hike (~> 1.2)
|
87
92
|
rack (~> 1.0)
|
@@ -93,6 +98,8 @@ GEM
|
|
93
98
|
polyglot
|
94
99
|
polyglot (>= 0.3.1)
|
95
100
|
tzinfo (0.3.31)
|
101
|
+
vegas (0.1.11)
|
102
|
+
rack (>= 1.0.0)
|
96
103
|
yard (0.6.8)
|
97
104
|
|
98
105
|
PLATFORMS
|
@@ -104,7 +111,8 @@ DEPENDENCIES
|
|
104
111
|
minitest
|
105
112
|
rails (>= 3.1.0)
|
106
113
|
redis (~> 2.2.0)
|
114
|
+
resque (~> 1.19.0)
|
115
|
+
resque-loner (~> 1.2.0)
|
107
116
|
shoulda
|
108
|
-
sidekiq
|
109
117
|
sqlite3
|
110
118
|
yard (~> 0.6.0)
|
@@ -8,5 +8,9 @@ module Recommendable
|
|
8
8
|
|
9
9
|
validates :user_id, :uniqueness => { :scope => [:dislikeable_id, :dislikeable_type],
|
10
10
|
:message => "has already disliked this item" }
|
11
|
+
|
12
|
+
def dislikeable_type=(sType)
|
13
|
+
super sType.to_s.classify.constantize.base_class.to_s
|
14
|
+
end
|
11
15
|
end
|
12
16
|
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
module Recommendable
|
2
2
|
class Ignore < ActiveRecord::Base
|
3
3
|
self.table_name = 'recommendable_ignores'
|
4
|
-
attr_accessible :user_id, :
|
4
|
+
attr_accessible :user_id, :ignorable_id, :ignorable_type
|
5
5
|
|
6
6
|
belongs_to :user, :class_name => Recommendable.user_class.to_s, :foreign_key => :user_id
|
7
|
-
belongs_to :
|
7
|
+
belongs_to :ignorable, :polymorphic => true
|
8
8
|
|
9
|
-
validates :user_id, :uniqueness => { :scope => [:
|
9
|
+
validates :user_id, :uniqueness => { :scope => [:ignorable_id, :ignorable_type],
|
10
10
|
:message => "has already ignored this item" }
|
11
|
+
def ignorable_type=(sType)
|
12
|
+
super sType.to_s.classify.constantize.base_class.to_s
|
13
|
+
end
|
11
14
|
end
|
12
15
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Recommendable
|
2
|
-
class
|
3
|
-
self.table_name = '
|
2
|
+
class Stash < ActiveRecord::Base
|
3
|
+
self.table_name = 'recommendable_stashes'
|
4
4
|
attr_accessible :user_id, :stashable_id, :stashable_type
|
5
5
|
|
6
6
|
belongs_to :user, :class_name => Recommendable.user_class.to_s, :foreign_key => :user_id
|
@@ -8,5 +8,8 @@ module Recommendable
|
|
8
8
|
|
9
9
|
validates :user_id, :uniqueness => { :scope => [:stashable_id, :stashable_type],
|
10
10
|
:message => "has already stashed this item" }
|
11
|
+
def stashable_type=(sType)
|
12
|
+
super sType.to_s.classify.constantize.base_class.to_s
|
13
|
+
end
|
11
14
|
end
|
12
15
|
end
|
@@ -2,13 +2,13 @@ class CreateIgnores < ActiveRecord::Migration
|
|
2
2
|
def up
|
3
3
|
create_table :recommendable_ignores do |t|
|
4
4
|
t.references :user
|
5
|
-
t.references :
|
5
|
+
t.references :ignorable, :polymorphic => true
|
6
6
|
t.timestamps
|
7
7
|
end
|
8
8
|
|
9
|
-
add_index :recommendable_ignores, :
|
10
|
-
add_index :recommendable_ignores, :
|
11
|
-
add_index :recommendable_ignores, [:user_id, :
|
9
|
+
add_index :recommendable_ignores, :ignorable_id
|
10
|
+
add_index :recommendable_ignores, :ignorable_type
|
11
|
+
add_index :recommendable_ignores, [:user_id, :ignorable_id, :ignorable_type], :unique => true, :name => "user_ignore_constraint"
|
12
12
|
end
|
13
13
|
|
14
14
|
def down
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateStashes < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
create_table :recommendable_stashes do |t|
|
4
|
+
t.references :user
|
5
|
+
t.references :stashable, :polymorphic => true
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :recommendable_stashes, :stashable_id
|
10
|
+
add_index :recommendable_stashes, :stashable_type
|
11
|
+
add_index :recommendable_stashes, [:user_id, :stashable_id, :stashable_type], :unique => true, :name => "user_stashed_constraint"
|
12
|
+
end
|
13
|
+
|
14
|
+
def down
|
15
|
+
drop_table :recommendable_stashes
|
16
|
+
end
|
17
|
+
end
|
data/lib/recommendable.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'recommendable/engine'
|
2
|
+
require 'recommendable/helpers'
|
2
3
|
require 'recommendable/acts_as_recommended_to'
|
3
4
|
require 'recommendable/acts_as_recommendable'
|
4
5
|
require 'recommendable/exceptions'
|
@@ -12,4 +13,8 @@ module Recommendable
|
|
12
13
|
def self.recommendable_classes
|
13
14
|
@@recommendable_classes ||= []
|
14
15
|
end
|
16
|
+
|
17
|
+
def self.enqueue(user_id)
|
18
|
+
Resque.enqueue RecommendationRefresher, user_id
|
19
|
+
end
|
15
20
|
end
|
@@ -7,12 +7,19 @@ module Recommendable
|
|
7
7
|
class_eval do
|
8
8
|
Recommendable.recommendable_classes << self
|
9
9
|
|
10
|
-
has_many :likes,
|
11
|
-
|
12
|
-
has_many :
|
13
|
-
|
14
|
-
has_many :
|
15
|
-
|
10
|
+
has_many :likes, :as => :likeable, :dependent => :destroy,
|
11
|
+
:class_name => "Recommendable::Like"
|
12
|
+
has_many :dislikes, :as => :dislikeable, :dependent => :destroy,
|
13
|
+
:class_name => "Recommendable::Dislike"
|
14
|
+
has_many :ignores, :as => :ignorable, :dependent => :destroy,
|
15
|
+
:class_name => "Recommendable::Ignore"
|
16
|
+
has_many :stashes, :as => :stashable, :dependent => :destroy,
|
17
|
+
:class_name => "Recommendable::Stash"
|
18
|
+
|
19
|
+
has_many :liked_by, :through => :likes, :source => :user, :foreign_key => :user_id,
|
20
|
+
:class_name => Recommendable.user_class.to_s
|
21
|
+
has_many :disliked_by, :through => :dislikes, :source => :user, :foreign_key => :user_id,
|
22
|
+
:class_name => Recommendable.user_class.to_s
|
16
23
|
|
17
24
|
include LikeableMethods
|
18
25
|
include DislikeableMethods
|
@@ -72,8 +79,8 @@ module Recommendable
|
|
72
79
|
# {#create_recommendable_sets}
|
73
80
|
# @private
|
74
81
|
def destroy_recommendable_sets
|
75
|
-
Recommendable.redis.del "#{self.class}:#{id}:liked_by"
|
76
|
-
Recommendable.redis.del "#{self.class}:#{id}:disliked_by"
|
82
|
+
Recommendable.redis.del "#{self.class.base_class}:#{id}:liked_by"
|
83
|
+
Recommendable.redis.del "#{self.class.base_class}:#{id}:disliked_by"
|
77
84
|
end
|
78
85
|
|
79
86
|
# Returns an array of IDs of users that have liked or disliked this item.
|
@@ -92,12 +99,16 @@ module Recommendable
|
|
92
99
|
end
|
93
100
|
|
94
101
|
def acts_as_recommendable?() false end
|
102
|
+
|
103
|
+
def sti?() self.base_class != self end
|
104
|
+
|
105
|
+
private
|
95
106
|
end
|
96
107
|
|
97
108
|
# Instance methods.
|
98
109
|
def recommendable?() self.class.acts_as_recommendable? end
|
99
110
|
|
100
|
-
def redis_key() "#{self.class}:#{id}" end
|
111
|
+
def redis_key() "#{self.class.base_class}:#{id}" end
|
101
112
|
|
102
113
|
protected :redis_key
|
103
114
|
|
@@ -2,6 +2,7 @@ require 'active_support/concern'
|
|
2
2
|
|
3
3
|
module Recommendable
|
4
4
|
module ActsAsRecommendedTo
|
5
|
+
include Recommendable::Helpers
|
5
6
|
extend ActiveSupport::Concern
|
6
7
|
|
7
8
|
module ClassMethods
|
@@ -17,7 +18,7 @@ module Recommendable
|
|
17
18
|
has_many :likes, :class_name => "Recommendable::Like", :dependent => :destroy, :foreign_key => :user_id
|
18
19
|
has_many :dislikes, :class_name => "Recommendable::Dislike", :dependent => :destroy, :foreign_key => :user_id
|
19
20
|
has_many :ignores, :class_name => "Recommendable::Ignore", :dependent => :destroy, :foreign_key => :user_id
|
20
|
-
has_many :stashed_items, :class_name => "Recommendable::
|
21
|
+
has_many :stashed_items, :class_name => "Recommendable::Stash", :dependent => :destroy, :foreign_key => :user_id
|
21
22
|
|
22
23
|
include LikeMethods
|
23
24
|
include DislikeMethods
|
@@ -81,9 +82,9 @@ module Recommendable
|
|
81
82
|
raise RecordNotRecommendableError unless object.recommendable?
|
82
83
|
return if likes? object
|
83
84
|
completely_unrecommend object
|
84
|
-
likes.create! :likeable_id => object.id, :likeable_type => object.class
|
85
|
+
likes.create! :likeable_id => object.id, :likeable_type => object.class
|
85
86
|
object.send :update_score
|
86
|
-
|
87
|
+
Recommendable.enqueue self.id
|
87
88
|
true
|
88
89
|
end
|
89
90
|
|
@@ -92,7 +93,7 @@ module Recommendable
|
|
92
93
|
# @param [Object] object the object you want to check
|
93
94
|
# @return true if self likes object, false if not
|
94
95
|
def likes? object
|
95
|
-
likes.exists? :likeable_id => object.id, :likeable_type => object.class.to_s
|
96
|
+
likes.exists? :likeable_id => object.id, :likeable_type => object.class.base_class.to_s
|
96
97
|
end
|
97
98
|
|
98
99
|
# Destroys a Recommendable::Like currently associating self with object
|
@@ -100,9 +101,9 @@ module Recommendable
|
|
100
101
|
# @param [Object] object the object you want to remove from self's likes
|
101
102
|
# @return true if object is unliked, nil if nothing happened
|
102
103
|
def unlike object
|
103
|
-
if likes.where(:likeable_id => object.id, :likeable_type => object.class.to_s).first.try(:destroy)
|
104
|
+
if likes.where(:likeable_id => object.id, :likeable_type => object.class.base_class.to_s).first.try(:destroy)
|
104
105
|
object.send :update_score
|
105
|
-
|
106
|
+
Recommendable.enqueue self.id
|
106
107
|
true
|
107
108
|
end
|
108
109
|
end
|
@@ -122,7 +123,13 @@ module Recommendable
|
|
122
123
|
# @param [Class, String, Symbol] klass the class of records. Can be the class constant, or a String/Symbol representation of the class name.
|
123
124
|
# @return [Array] an array of ActiveRecord objects that self has liked belonging to klass
|
124
125
|
def liked_for klass
|
125
|
-
|
126
|
+
liked = if klass.sti?
|
127
|
+
likes.joins manual_join(klass, 'like')
|
128
|
+
else
|
129
|
+
likes.where(:likeable_type => klass.to_s).includes(:likeable)
|
130
|
+
end
|
131
|
+
|
132
|
+
liked.map(&:likeable)
|
126
133
|
end
|
127
134
|
|
128
135
|
# Get a list of Recommendable::Likes with a `#likeable_type` of the passed
|
@@ -132,7 +139,11 @@ module Recommendable
|
|
132
139
|
# @note You should not need to use this method. (see {#liked_for})
|
133
140
|
# @private
|
134
141
|
def likes_for klass
|
135
|
-
|
142
|
+
if klass.sti?
|
143
|
+
likes.joins manual_join(klass, 'like')
|
144
|
+
else
|
145
|
+
likes.where(:likeable_type => klass.to_s)
|
146
|
+
end
|
136
147
|
end
|
137
148
|
end
|
138
149
|
|
@@ -149,9 +160,9 @@ module Recommendable
|
|
149
160
|
raise RecordNotRecommendableError unless object.recommendable?
|
150
161
|
return if dislikes? object
|
151
162
|
completely_unrecommend object
|
152
|
-
dislikes.create! :dislikeable_id => object.id, :dislikeable_type => object.class
|
163
|
+
dislikes.create! :dislikeable_id => object.id, :dislikeable_type => object.class
|
153
164
|
object.send :update_score
|
154
|
-
|
165
|
+
Recommendable.enqueue self.id
|
155
166
|
true
|
156
167
|
end
|
157
168
|
|
@@ -160,7 +171,7 @@ module Recommendable
|
|
160
171
|
# @param [Object] object the object you want to check
|
161
172
|
# @return true if self dislikes object, false if not
|
162
173
|
def dislikes? object
|
163
|
-
dislikes.exists? :dislikeable_id => object.id, :dislikeable_type => object.class.to_s
|
174
|
+
dislikes.exists? :dislikeable_id => object.id, :dislikeable_type => object.class.base_class.to_s
|
164
175
|
end
|
165
176
|
|
166
177
|
# Destroys a Recommendable::Dislike currently associating self with object
|
@@ -168,9 +179,9 @@ module Recommendable
|
|
168
179
|
# @param [Object] object the object you want to remove from self's dislikes
|
169
180
|
# @return true if object is removed from self's dislikes, nil if nothing happened
|
170
181
|
def undislike object
|
171
|
-
if dislikes.where(:dislikeable_id => object.id, :dislikeable_type => object.class.to_s).first.try(:destroy)
|
182
|
+
if dislikes.where(:dislikeable_id => object.id, :dislikeable_type => object.class.base_class.to_s).first.try(:destroy)
|
172
183
|
object.send :update_score
|
173
|
-
|
184
|
+
Recommendable.enqueue self.id
|
174
185
|
true
|
175
186
|
end
|
176
187
|
end
|
@@ -190,7 +201,13 @@ module Recommendable
|
|
190
201
|
# @param [Class, String, Symbol] klass the class of records. Can be the class constant, or a String/Symbol representation of the class name.
|
191
202
|
# @return [Array] an array of ActiveRecord objects that self has disliked belonging to klass
|
192
203
|
def disliked_for klass
|
193
|
-
|
204
|
+
disliked = if klass.sti?
|
205
|
+
dislikes.joins manual_join(klass, 'dislike')
|
206
|
+
else
|
207
|
+
dislikes.where(:dislikeable_type => klass.to_s).includes(:dislikeable)
|
208
|
+
end
|
209
|
+
|
210
|
+
disliked.map(&:dislikeable)
|
194
211
|
end
|
195
212
|
|
196
213
|
# Get a list of Recommendable::Dislikes with a `#dislikeable_type` of the
|
@@ -200,12 +217,16 @@ module Recommendable
|
|
200
217
|
# @note You should not need to use this method. (see {#disliked_for})
|
201
218
|
# @private
|
202
219
|
def dislikes_for klass
|
203
|
-
|
220
|
+
if klass.sti?
|
221
|
+
dislikes.joins manual_join(klass, 'dislike')
|
222
|
+
else
|
223
|
+
dislikes.where(:dislikeable_type => klass.to_s)
|
224
|
+
end
|
204
225
|
end
|
205
226
|
end
|
206
227
|
|
207
228
|
module StashMethods
|
208
|
-
# Creates a Recommendable::
|
229
|
+
# Creates a Recommendable::Stash to associate self to a passed object.
|
209
230
|
# This will remove the item from this user's recommendations.
|
210
231
|
# If self is currently found to have liked or disliked the object, nothing
|
211
232
|
# will happen. It will, however, be unignored.
|
@@ -218,7 +239,7 @@ module Recommendable
|
|
218
239
|
return if rated?(object) || stashed?(object)
|
219
240
|
unignore object
|
220
241
|
unpredict object
|
221
|
-
stashed_items.create! :stashable_id => object.id, :stashable_type => object.class
|
242
|
+
stashed_items.create! :stashable_id => object.id, :stashable_type => object.class
|
222
243
|
true
|
223
244
|
end
|
224
245
|
|
@@ -227,15 +248,15 @@ module Recommendable
|
|
227
248
|
# @param [Object] object the object you want to check
|
228
249
|
# @return true if self has stashed object, false if not
|
229
250
|
def stashed? object
|
230
|
-
stashed_items.exists? :stashable_id => object.id, :stashable_type => object.class.to_s
|
251
|
+
stashed_items.exists? :stashable_id => object.id, :stashable_type => object.class.base_class.to_s
|
231
252
|
end
|
232
253
|
|
233
|
-
# Destroys a Recommendable::
|
254
|
+
# Destroys a Recommendable::Stash currently associating self with object
|
234
255
|
#
|
235
256
|
# @param [Object] object the object you want to remove from self's stash
|
236
257
|
# @return true if object is stashed, nil if nothing happened
|
237
258
|
def unstash object
|
238
|
-
true if stashed_items.where(:stashable_id => object.id, :stashable_type => object.class.to_s).first.try(:destroy)
|
259
|
+
true if stashed_items.where(:stashable_id => object.id, :stashable_type => object.class.base_class.to_s).first.try(:destroy)
|
239
260
|
end
|
240
261
|
|
241
262
|
# Get a list of records that self has currently stashed for later
|
@@ -253,7 +274,13 @@ module Recommendable
|
|
253
274
|
# @param [Class, String, Symbol] klass the class of records. Can be the class constant, or a String/Symbol representation of the class name.
|
254
275
|
# @return [Array] an array of ActiveRecord objects that self has stashed belonging to klass
|
255
276
|
def stashed_for klass
|
256
|
-
|
277
|
+
stashed = if klass.sti?
|
278
|
+
stashed_items.joins manual_join(klass, 'stash')
|
279
|
+
else
|
280
|
+
stashed_items.where(:stashable_type => klass.to_s).includes(:stashable)
|
281
|
+
end
|
282
|
+
|
283
|
+
stashed.map(&:stashable)
|
257
284
|
end
|
258
285
|
end
|
259
286
|
|
@@ -270,7 +297,7 @@ module Recommendable
|
|
270
297
|
raise RecordNotRecommendableError unless object.recommendable?
|
271
298
|
return if ignored? object
|
272
299
|
completely_unrecommend object
|
273
|
-
ignores.create! :
|
300
|
+
ignores.create! :ignorable_id => object.id, :ignorable_type => object.class
|
274
301
|
true
|
275
302
|
end
|
276
303
|
|
@@ -279,7 +306,7 @@ module Recommendable
|
|
279
306
|
# @param [Object] object the object you want to check
|
280
307
|
# @return true if self has ignored object, false if not
|
281
308
|
def ignored? object
|
282
|
-
ignores.exists? :
|
309
|
+
ignores.exists? :ignorable_id => object.id, :ignorable_type => object.class.base_class.to_s
|
283
310
|
end
|
284
311
|
|
285
312
|
# Destroys a Recommendable::Ignore currently associating self with object
|
@@ -287,7 +314,7 @@ module Recommendable
|
|
287
314
|
# @param [Object] object the object you want to remove from self's ignores
|
288
315
|
# @return true if object is removed from self's ignores, nil if nothing happened
|
289
316
|
def unignore object
|
290
|
-
true if ignores.where(:
|
317
|
+
true if ignores.where(:ignorable_id => object.id, :ignorable_type => object.class.base_class.to_s).first.try(:destroy)
|
291
318
|
end
|
292
319
|
|
293
320
|
# Get a list of records that self is currently ignoring
|
@@ -305,7 +332,13 @@ module Recommendable
|
|
305
332
|
# @param [Class, String, Symbol] klass the class of records. Can be the class constant, or a String/Symbol representation of the class name.
|
306
333
|
# @return [Array] an array of ActiveRecord objects that self has ignored belonging to klass
|
307
334
|
def ignored_for klass
|
308
|
-
|
335
|
+
ignored = if klass.sti?
|
336
|
+
ignores.joins manual_join(klass, 'ignore')
|
337
|
+
else
|
338
|
+
ignores.where(:ignorable_type => klass.to_s).includes(:ignorable)
|
339
|
+
end
|
340
|
+
|
341
|
+
ignored.map(&:ignorable)
|
309
342
|
end
|
310
343
|
end
|
311
344
|
|
@@ -397,7 +430,8 @@ module Recommendable
|
|
397
430
|
# @param [Class, String, Symbol] klass the class to receive recommendations for. Can be the class constant, or a String/Symbol representation of the class name.
|
398
431
|
# @return [Array] an array of ActiveRecord objects that are recommendable
|
399
432
|
def recommended_for klass
|
400
|
-
return [] if likes_for(klass).count + dislikes_for(klass).count == 0 ||
|
433
|
+
return [] if likes_for(klass.base_class).count + dislikes_for(klass.base_class).count == 0 || \
|
434
|
+
Recommendable.redis.zcard(predictions_set_for(klass)) == 0
|
401
435
|
|
402
436
|
recommendations = []
|
403
437
|
i = 0
|
@@ -3,13 +3,13 @@ class CreateIgnores < ActiveRecord::Migration
|
|
3
3
|
def up
|
4
4
|
create_table :recommendable_ignores, :force => true do |t|
|
5
5
|
t.references :user
|
6
|
-
t.references :
|
6
|
+
t.references :ignorable, :polymorphic => true
|
7
7
|
t.timestamps
|
8
8
|
end
|
9
9
|
|
10
|
-
add_index :recommendable_ignores, :
|
11
|
-
add_index :recommendable_ignores, :
|
12
|
-
add_index :recommendable_ignores, [:user_id, :
|
10
|
+
add_index :recommendable_ignores, :ignorable_id
|
11
|
+
add_index :recommendable_ignores, :ignorable_type
|
12
|
+
add_index :recommendable_ignores, [:user_id, :ignorable_id, :ignorable_type], :unique => true, :name => "user_ignore_constraint"
|
13
13
|
end
|
14
14
|
|
15
15
|
def down
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This migration comes from recommendable (originally 20120131173909)
|
2
|
+
class CreateStashes < ActiveRecord::Migration
|
3
|
+
def up
|
4
|
+
create_table :recommendable_stashes do |t|
|
5
|
+
t.references :user
|
6
|
+
t.references :stashable, :polymorphic => true
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :recommendable_stashes, :stashable_id
|
11
|
+
add_index :recommendable_stashes, :stashable_type
|
12
|
+
add_index :recommendable_stashes, [:user_id, :stashable_id, :stashable_type], :unique => true, :name => "user_stashed_constraint"
|
13
|
+
end
|
14
|
+
|
15
|
+
def down
|
16
|
+
drop_table :recommendable_stashes
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -46,15 +46,15 @@ ActiveRecord::Schema.define(:version => 20120131195416) do
|
|
46
46
|
|
47
47
|
create_table "recommendable_ignores", :force => true do |t|
|
48
48
|
t.integer "user_id"
|
49
|
-
t.integer "
|
50
|
-
t.string "
|
51
|
-
t.datetime "created_at",
|
52
|
-
t.datetime "updated_at",
|
49
|
+
t.integer "ignorable_id"
|
50
|
+
t.string "ignorable_type"
|
51
|
+
t.datetime "created_at", :null => false
|
52
|
+
t.datetime "updated_at", :null => false
|
53
53
|
end
|
54
54
|
|
55
|
-
add_index "recommendable_ignores", ["
|
56
|
-
add_index "recommendable_ignores", ["
|
57
|
-
add_index "recommendable_ignores", ["user_id", "
|
55
|
+
add_index "recommendable_ignores", ["ignorable_id"], :name => "index_recommendable_ignores_on_ignorable_id"
|
56
|
+
add_index "recommendable_ignores", ["ignorable_type"], :name => "index_recommendable_ignores_on_ignorable_type"
|
57
|
+
add_index "recommendable_ignores", ["user_id", "ignorable_id", "ignorable_type"], :name => "user_ignore_constraint", :unique => true
|
58
58
|
|
59
59
|
create_table "recommendable_likes", :force => true do |t|
|
60
60
|
t.integer "user_id"
|
@@ -68,7 +68,7 @@ ActiveRecord::Schema.define(:version => 20120131195416) do
|
|
68
68
|
add_index "recommendable_likes", ["likeable_type"], :name => "index_recommendable_likes_on_likeable_type"
|
69
69
|
add_index "recommendable_likes", ["user_id", "likeable_id", "likeable_type"], :name => "user_like_constraint", :unique => true
|
70
70
|
|
71
|
-
create_table "
|
71
|
+
create_table "recommendable_stashes", :force => true do |t|
|
72
72
|
t.integer "user_id"
|
73
73
|
t.integer "stashable_id"
|
74
74
|
t.string "stashable_type"
|
@@ -76,9 +76,9 @@ ActiveRecord::Schema.define(:version => 20120131195416) do
|
|
76
76
|
t.datetime "updated_at", :null => false
|
77
77
|
end
|
78
78
|
|
79
|
-
add_index "
|
80
|
-
add_index "
|
81
|
-
add_index "
|
79
|
+
add_index "recommendable_stashes", ["stashable_id"], :name => "index_recommendable_stashes_on_stashable_id"
|
80
|
+
add_index "recommendable_stashes", ["stashable_type"], :name => "index_recommendable_stashes_on_stashable_type"
|
81
|
+
add_index "recommendable_stashes", ["user_id", "stashable_id", "stashable_type"], :name => "user_stashed_constraint", :unique => true
|
82
82
|
|
83
83
|
create_table "users", :force => true do |t|
|
84
84
|
t.string "username"
|
Binary file
|
Binary file
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class
|
4
|
-
describe Recommendable::
|
3
|
+
class StashSpec < MiniTest::Spec
|
4
|
+
describe Recommendable::Stash do
|
5
5
|
before :each do
|
6
6
|
@user = User.create(:username => "dave")
|
7
7
|
end
|
@@ -21,7 +21,7 @@ class StashedItemSpec < MiniTest::Spec
|
|
21
21
|
|
22
22
|
@user.stash(movie).must_equal true
|
23
23
|
@user.stash(movie).must_be_nil
|
24
|
-
Recommendable::
|
24
|
+
Recommendable::Stash.count.must_equal 1
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recommendable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.2.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sqlite3
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: minitest
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: shoulda
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: yard
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ~>
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: 0.6.0
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.6.0
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: bundler
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ~>
|
@@ -65,10 +85,15 @@ dependencies:
|
|
65
85
|
version: 1.0.0
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.0.0
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: jeweler
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ~>
|
@@ -76,10 +101,15 @@ dependencies:
|
|
76
101
|
version: 1.6.4
|
77
102
|
type: :development
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.6.4
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: rcov
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
115
|
- - ! '>='
|
@@ -87,10 +117,15 @@ dependencies:
|
|
87
117
|
version: '0'
|
88
118
|
type: :development
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: rails
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
131
|
- - ! '>='
|
@@ -98,10 +133,15 @@ dependencies:
|
|
98
133
|
version: 3.0.0
|
99
134
|
type: :runtime
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 3.0.0
|
102
142
|
- !ruby/object:Gem::Dependency
|
103
143
|
name: redis
|
104
|
-
requirement:
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
105
145
|
none: false
|
106
146
|
requirements:
|
107
147
|
- - ~>
|
@@ -109,10 +149,15 @@ dependencies:
|
|
109
149
|
version: 2.2.0
|
110
150
|
type: :runtime
|
111
151
|
prerelease: false
|
112
|
-
version_requirements:
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 2.2.0
|
113
158
|
- !ruby/object:Gem::Dependency
|
114
159
|
name: resque
|
115
|
-
requirement:
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
116
161
|
none: false
|
117
162
|
requirements:
|
118
163
|
- - ! '>='
|
@@ -120,10 +165,15 @@ dependencies:
|
|
120
165
|
version: 1.19.0
|
121
166
|
type: :runtime
|
122
167
|
prerelease: false
|
123
|
-
version_requirements:
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 1.19.0
|
124
174
|
- !ruby/object:Gem::Dependency
|
125
175
|
name: resque-loner
|
126
|
-
requirement:
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
127
177
|
none: false
|
128
178
|
requirements:
|
129
179
|
- - ~>
|
@@ -131,7 +181,12 @@ dependencies:
|
|
131
181
|
version: 1.2.0
|
132
182
|
type: :runtime
|
133
183
|
prerelease: false
|
134
|
-
version_requirements:
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ~>
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: 1.2.0
|
135
190
|
description: Allow a model (typically User) to Like and/or Dislike models in your
|
136
191
|
app. Generate recommendations quickly using redis.
|
137
192
|
email: david@davidcelis.com
|
@@ -151,13 +206,13 @@ files:
|
|
151
206
|
- app/models/recommendable/dislike.rb
|
152
207
|
- app/models/recommendable/ignore.rb
|
153
208
|
- app/models/recommendable/like.rb
|
154
|
-
- app/models/recommendable/
|
209
|
+
- app/models/recommendable/stash.rb
|
155
210
|
- app/workers/recommendable/recommendation_refresher.rb
|
156
211
|
- config/routes.rb
|
157
212
|
- db/migrate/20120124193723_create_likes.rb
|
158
213
|
- db/migrate/20120124193728_create_dislikes.rb
|
159
214
|
- db/migrate/20120127092558_create_ignores.rb
|
160
|
-
- db/migrate/
|
215
|
+
- db/migrate/20120131173909_create_stashes.rb
|
161
216
|
- lib/generators/recommendable/USAGE
|
162
217
|
- lib/generators/recommendable/install_generator.rb
|
163
218
|
- lib/generators/recommendable/templates/initializer.rb
|
@@ -166,6 +221,7 @@ files:
|
|
166
221
|
- lib/recommendable/acts_as_recommended_to.rb
|
167
222
|
- lib/recommendable/engine.rb
|
168
223
|
- lib/recommendable/exceptions.rb
|
224
|
+
- lib/recommendable/helpers.rb
|
169
225
|
- lib/recommendable/railtie.rb
|
170
226
|
- lib/recommendable/version.rb
|
171
227
|
- lib/tasks/recommendable_tasks.rake
|
@@ -209,7 +265,7 @@ files:
|
|
209
265
|
- spec/dummy/db/migrate/20120128020413_create_movies.rb
|
210
266
|
- spec/dummy/db/migrate/20120128024632_create_php_frameworks.rb
|
211
267
|
- spec/dummy/db/migrate/20120128024804_create_bullies.rb
|
212
|
-
- spec/dummy/db/migrate/
|
268
|
+
- spec/dummy/db/migrate/20120131195416_create_stashes.recommendable.rb
|
213
269
|
- spec/dummy/db/schema.rb
|
214
270
|
- spec/dummy/lib/assets/.gitkeep
|
215
271
|
- spec/dummy/log/.gitkeep
|
@@ -225,7 +281,7 @@ files:
|
|
225
281
|
- spec/models/ignore_spec.rb
|
226
282
|
- spec/models/like_spec.rb
|
227
283
|
- spec/models/movie_spec.rb
|
228
|
-
- spec/models/
|
284
|
+
- spec/models/stash_spec.rb
|
229
285
|
- spec/models/user_benchmark_spec.rb
|
230
286
|
- spec/models/user_spec.rb
|
231
287
|
- spec/spec_helper.rb
|
@@ -249,7 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
249
305
|
version: '0'
|
250
306
|
requirements: []
|
251
307
|
rubyforge_project:
|
252
|
-
rubygems_version: 1.8.
|
308
|
+
rubygems_version: 1.8.22
|
253
309
|
signing_key:
|
254
310
|
specification_version: 3
|
255
311
|
summary: Add like-based and/or dislike-based recommendations to your app.
|
@@ -1,17 +0,0 @@
|
|
1
|
-
class CreateStashedItems < ActiveRecord::Migration
|
2
|
-
def up
|
3
|
-
create_table :recommendable_stashed_items do |t|
|
4
|
-
t.references :user
|
5
|
-
t.references :stashable, :polymorphic => true
|
6
|
-
t.timestamps
|
7
|
-
end
|
8
|
-
|
9
|
-
add_index :recommendable_stashed_items, :stashable_id
|
10
|
-
add_index :recommendable_stashed_items, :stashable_type
|
11
|
-
add_index :recommendable_stashed_items, [:user_id, :stashable_id, :stashable_type], :unique => true, :name => "user_stashed_constraint"
|
12
|
-
end
|
13
|
-
|
14
|
-
def down
|
15
|
-
drop_table :recommendable_stashed_items
|
16
|
-
end
|
17
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# This migration comes from recommendable (originally 20120131173909)
|
2
|
-
class CreateStashedItems < ActiveRecord::Migration
|
3
|
-
def up
|
4
|
-
create_table :recommendable_stashed_items do |t|
|
5
|
-
t.references :user
|
6
|
-
t.references :stashable, :polymorphic => true
|
7
|
-
t.timestamps
|
8
|
-
end
|
9
|
-
|
10
|
-
add_index :recommendable_stashed_items, :stashable_id
|
11
|
-
add_index :recommendable_stashed_items, :stashable_type
|
12
|
-
add_index :recommendable_stashed_items, [:user_id, :stashable_id, :stashable_type], :unique => true, :name => "user_stashed_constraint"
|
13
|
-
end
|
14
|
-
|
15
|
-
def down
|
16
|
-
drop_table :recommendable_stashed_items
|
17
|
-
end
|
18
|
-
end
|