recommendable 1.1.7 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/recommendable.rb +38 -26
- data/lib/recommendable/configuration.rb +47 -0
- data/lib/recommendable/helpers.rb +3 -9
- data/lib/recommendable/helpers/calculations.rb +150 -0
- data/lib/recommendable/helpers/queriers.rb +23 -0
- data/lib/recommendable/helpers/redis_key_mapper.rb +29 -0
- data/lib/recommendable/orm/active_record.rb +6 -0
- data/lib/recommendable/orm/data_mapper.rb +7 -0
- data/lib/recommendable/orm/mongo_mapper.rb +8 -0
- data/lib/recommendable/orm/mongoid.rb +7 -0
- data/lib/recommendable/ratable.rb +83 -0
- data/lib/recommendable/ratable/dislikable.rb +26 -0
- data/lib/recommendable/ratable/likable.rb +26 -0
- data/lib/recommendable/rater.rb +109 -0
- data/lib/recommendable/rater/bookmarker.rb +120 -0
- data/lib/recommendable/rater/disliker.rb +122 -0
- data/lib/recommendable/rater/hider.rb +120 -0
- data/lib/recommendable/rater/liker.rb +122 -0
- data/lib/recommendable/rater/recommender.rb +68 -0
- data/lib/recommendable/version.rb +5 -4
- data/lib/recommendable/workers/delayed_job.rb +16 -0
- data/lib/recommendable/workers/rails.rb +16 -0
- data/lib/recommendable/workers/resque.rb +13 -0
- data/lib/recommendable/workers/sidekiq.rb +13 -0
- metadata +62 -131
- data/.gitignore +0 -57
- data/.travis.yml +0 -3
- data/CHANGELOG.markdown +0 -159
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -112
- data/LICENSE.txt +0 -22
- data/README.markdown +0 -135
- data/Rakefile +0 -26
- data/TODO +0 -7
- data/app/models/recommendable/dislike.rb +0 -19
- data/app/models/recommendable/ignore.rb +0 -19
- data/app/models/recommendable/like.rb +0 -19
- data/app/models/recommendable/stash.rb +0 -19
- data/app/workers/recommendable/delayed_job_worker.rb +0 -17
- data/app/workers/recommendable/rails_worker.rb +0 -17
- data/app/workers/recommendable/resque_worker.rb +0 -14
- data/app/workers/recommendable/sidekiq_worker.rb +0 -14
- data/config/routes.rb +0 -3
- data/db/migrate/20120124193723_create_likes.rb +0 -17
- data/db/migrate/20120124193728_create_dislikes.rb +0 -17
- data/db/migrate/20120127092558_create_ignores.rb +0 -17
- data/db/migrate/20120131173909_create_stashes.rb +0 -17
- data/lib/generators/recommendable/USAGE +0 -8
- data/lib/generators/recommendable/install_generator.rb +0 -40
- data/lib/generators/recommendable/templates/initializer.rb +0 -28
- data/lib/recommendable/acts_as_recommendable.rb +0 -176
- data/lib/recommendable/acts_as_recommended_to.rb +0 -774
- data/lib/recommendable/engine.rb +0 -14
- data/lib/recommendable/exceptions.rb +0 -4
- data/lib/recommendable/railtie.rb +0 -6
- data/lib/sidekiq/middleware/client/unique_jobs.rb +0 -37
- data/lib/sidekiq/middleware/server/unique_jobs.rb +0 -17
- data/lib/tasks/recommendable_tasks.rake +0 -1
- data/recommendable.gemspec +0 -30
- data/script/rails +0 -8
- data/spec/configuration_spec.rb +0 -9
- data/spec/dummy/README.rdoc +0 -261
- data/spec/dummy/Rakefile +0 -7
- data/spec/dummy/app/assets/javascripts/application.js +0 -15
- data/spec/dummy/app/assets/stylesheets/application.css +0 -13
- data/spec/dummy/app/controllers/application_controller.rb +0 -3
- data/spec/dummy/app/helpers/application_helper.rb +0 -2
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/bully.rb +0 -2
- data/spec/dummy/app/models/movie.rb +0 -2
- data/spec/dummy/app/models/php_framework.rb +0 -2
- data/spec/dummy/app/models/user.rb +0 -3
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/config/application.rb +0 -56
- data/spec/dummy/config/boot.rb +0 -10
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -37
- data/spec/dummy/config/environments/production.rb +0 -67
- data/spec/dummy/config/environments/test.rb +0 -37
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/inflections.rb +0 -15
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/dummy/config/initializers/recommendable.rb +0 -14
- data/spec/dummy/config/initializers/secret_token.rb +0 -7
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/locales/en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -4
- data/spec/dummy/db/migrate/20120128005553_create_likes.recommendable.rb +0 -18
- data/spec/dummy/db/migrate/20120128005554_create_dislikes.recommendable.rb +0 -18
- data/spec/dummy/db/migrate/20120128005555_create_ignores.recommendable.rb +0 -18
- data/spec/dummy/db/migrate/20120128020228_create_users.rb +0 -9
- data/spec/dummy/db/migrate/20120128020413_create_movies.rb +0 -10
- data/spec/dummy/db/migrate/20120128024632_create_php_frameworks.rb +0 -9
- data/spec/dummy/db/migrate/20120128024804_create_bullies.rb +0 -9
- data/spec/dummy/db/migrate/20120131195416_create_stashes.recommendable.rb +0 -19
- data/spec/dummy/db/schema.rb +0 -89
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -25
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/recommendable_dummy_development +0 -0
- data/spec/dummy/recommendable_dummy_test +0 -0
- data/spec/dummy/script/rails +0 -6
- data/spec/factories.rb +0 -16
- data/spec/models/dislike_spec.rb +0 -41
- data/spec/models/ignore_spec.rb +0 -27
- data/spec/models/like_spec.rb +0 -42
- data/spec/models/movie_spec.rb +0 -82
- data/spec/models/stash_spec.rb +0 -27
- data/spec/models/user_benchmark_spec.rb +0 -49
- data/spec/models/user_spec.rb +0 -443
- data/spec/spec_helper.rb +0 -28
data/Rakefile
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bundler'
|
5
|
-
|
6
|
-
begin
|
7
|
-
Bundler.setup(:default, :development)
|
8
|
-
rescue Bundler::BundlerError => e
|
9
|
-
$stderr.puts e.message
|
10
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
-
exit e.status_code
|
12
|
-
end
|
13
|
-
|
14
|
-
require 'rake'
|
15
|
-
|
16
|
-
require 'rake/testtask'
|
17
|
-
Rake::TestTask.new(:test) do |test|
|
18
|
-
test.libs << 'lib' << 'spec'
|
19
|
-
test.pattern = 'spec/**/*_spec.rb'
|
20
|
-
test.verbose = true
|
21
|
-
end
|
22
|
-
|
23
|
-
task :default => :test
|
24
|
-
|
25
|
-
require 'yard'
|
26
|
-
YARD::Rake::YardocTask.new
|
data/TODO
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
class Dislike < ActiveRecord::Base
|
3
|
-
self.table_name = 'recommendable_dislikes'
|
4
|
-
attr_accessible :user_id, :dislikeable_id, :dislikeable_type
|
5
|
-
|
6
|
-
belongs_to :user, :class_name => Recommendable.user_class.to_s, :foreign_key => :user_id
|
7
|
-
belongs_to :dislikeable, :polymorphic => true
|
8
|
-
|
9
|
-
validates :user_id, :uniqueness => { :scope => [:dislikeable_id, :dislikeable_type],
|
10
|
-
:message => "has already disliked this item" },
|
11
|
-
:presence => true
|
12
|
-
validates_presence_of :dislikeable_id
|
13
|
-
validates_presence_of :dislikeable_type
|
14
|
-
|
15
|
-
def dislikeable_type=(sType)
|
16
|
-
super sType.to_s.classify.constantize.base_class.to_s
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
class Ignore < ActiveRecord::Base
|
3
|
-
self.table_name = 'recommendable_ignores'
|
4
|
-
attr_accessible :user_id, :ignorable_id, :ignorable_type
|
5
|
-
|
6
|
-
belongs_to :user, :class_name => Recommendable.user_class.to_s, :foreign_key => :user_id
|
7
|
-
belongs_to :ignorable, :polymorphic => true
|
8
|
-
|
9
|
-
validates :user_id, :uniqueness => { :scope => [:ignorable_id, :ignorable_type],
|
10
|
-
:message => "has already ignored this item" },
|
11
|
-
:presence => true
|
12
|
-
validates_presence_of :ignorable_id
|
13
|
-
validates_presence_of :ignorable_type
|
14
|
-
|
15
|
-
def ignorable_type=(sType)
|
16
|
-
super sType.to_s.classify.constantize.base_class.to_s
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
class Like < ActiveRecord::Base
|
3
|
-
self.table_name = 'recommendable_likes'
|
4
|
-
attr_accessible :user_id, :likeable_id, :likeable_type
|
5
|
-
|
6
|
-
belongs_to :user, :class_name => Recommendable.user_class.to_s, :foreign_key => :user_id
|
7
|
-
belongs_to :likeable, :polymorphic => true, :foreign_key => :likeable_id
|
8
|
-
|
9
|
-
validates :user_id, :uniqueness => { :scope => [:likeable_id, :likeable_type],
|
10
|
-
:message => "has already liked this item" },
|
11
|
-
:presence => true
|
12
|
-
validates_presence_of :likeable_id
|
13
|
-
validates_presence_of :likeable_type
|
14
|
-
|
15
|
-
def likeable_type=(sType)
|
16
|
-
super sType.to_s.classify.constantize.base_class.to_s
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
class Stash < ActiveRecord::Base
|
3
|
-
self.table_name = 'recommendable_stashes'
|
4
|
-
attr_accessible :user_id, :stashable_id, :stashable_type
|
5
|
-
|
6
|
-
belongs_to :user, :class_name => Recommendable.user_class.to_s, :foreign_key => :user_id
|
7
|
-
belongs_to :stashable, :polymorphic => :true
|
8
|
-
|
9
|
-
validates :user_id, :uniqueness => { :scope => [:stashable_id, :stashable_type],
|
10
|
-
:message => "has already stashed this item" },
|
11
|
-
:presence => true
|
12
|
-
validates_presence_of :stashable_id
|
13
|
-
validates_presence_of :stashable_type
|
14
|
-
|
15
|
-
def stashable_type=(sType)
|
16
|
-
super sType.to_s.classify.constantize.base_class.to_s
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
if defined?(Delayed::Job)
|
3
|
-
class DelayedJobWorker
|
4
|
-
attr_accessor :user_id
|
5
|
-
|
6
|
-
def initialize(user_id)
|
7
|
-
@user_id = user_id
|
8
|
-
end
|
9
|
-
|
10
|
-
def perform
|
11
|
-
user = Recommendable.user_class.find(self.user_id)
|
12
|
-
user.send :update_similarities
|
13
|
-
user.send :update_recommendations
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
if defined?(Rails::Queueing)
|
3
|
-
class RailsWorker
|
4
|
-
attr_accessor :user_id
|
5
|
-
|
6
|
-
def initialize(user_id)
|
7
|
-
@user_id = user_id
|
8
|
-
end
|
9
|
-
|
10
|
-
def run
|
11
|
-
user = Recommendable.user_class.find(self.user_id)
|
12
|
-
user.send :update_similarities
|
13
|
-
user.send :update_recommendations
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
if defined?(Resque)
|
3
|
-
class ResqueWorker
|
4
|
-
include Resque::Plugins::UniqueJob if defined?(Resque::Plugins::UniqueJob)
|
5
|
-
@queue = :recommendable
|
6
|
-
|
7
|
-
def self.perform(user_id)
|
8
|
-
user = Recommendable.user_class.find(user_id)
|
9
|
-
user.send :update_similarities
|
10
|
-
user.send :update_recommendations
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
if defined?(Sidekiq)
|
3
|
-
class SidekiqWorker
|
4
|
-
include ::Sidekiq::Worker
|
5
|
-
sidekiq_options :queue => :recommendable, :unique => true
|
6
|
-
|
7
|
-
def perform(user_id)
|
8
|
-
user = Recommendable.user_class.find(user_id)
|
9
|
-
user.send :update_similarities
|
10
|
-
user.send :update_recommendations
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/config/routes.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
class CreateLikes < ActiveRecord::Migration
|
2
|
-
def up
|
3
|
-
create_table :recommendable_likes do |t|
|
4
|
-
t.references :user
|
5
|
-
t.references :likeable, :polymorphic => true
|
6
|
-
t.timestamps
|
7
|
-
end
|
8
|
-
|
9
|
-
add_index :recommendable_likes, :likeable_id
|
10
|
-
add_index :recommendable_likes, :likeable_type
|
11
|
-
add_index :recommendable_likes, [:user_id, :likeable_id, :likeable_type], :unique => true, :name => "user_like_constraint"
|
12
|
-
end
|
13
|
-
|
14
|
-
def down
|
15
|
-
drop_table :recommendable_likes
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
class CreateDislikes < ActiveRecord::Migration
|
2
|
-
def up
|
3
|
-
create_table :recommendable_dislikes do |t|
|
4
|
-
t.references :user
|
5
|
-
t.references :dislikeable, :polymorphic => true
|
6
|
-
t.timestamps
|
7
|
-
end
|
8
|
-
|
9
|
-
add_index :recommendable_dislikes, :dislikeable_id
|
10
|
-
add_index :recommendable_dislikes, :dislikeable_type
|
11
|
-
add_index :recommendable_dislikes, [:user_id, :dislikeable_id, :dislikeable_type], :unique => true, :name => "user_dislike_constraint"
|
12
|
-
end
|
13
|
-
|
14
|
-
def down
|
15
|
-
drop_table :recommendable_dislikes
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
class CreateIgnores < ActiveRecord::Migration
|
2
|
-
def up
|
3
|
-
create_table :recommendable_ignores do |t|
|
4
|
-
t.references :user
|
5
|
-
t.references :ignorable, :polymorphic => true
|
6
|
-
t.timestamps
|
7
|
-
end
|
8
|
-
|
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
|
-
end
|
13
|
-
|
14
|
-
def down
|
15
|
-
drop_table :recommendable_ignores
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
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
|
@@ -1,8 +0,0 @@
|
|
1
|
-
Description:
|
2
|
-
This generator will install Recommendable's initializer.rb file and migrate the Like and Dislike tables into your database unless specified.
|
3
|
-
|
4
|
-
Example:
|
5
|
-
rails generate recommendable:install
|
6
|
-
|
7
|
-
This will create:
|
8
|
-
config/initializers/recommendable.rb
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'rails/generators'
|
2
|
-
|
3
|
-
module Recommendable
|
4
|
-
module Generators
|
5
|
-
class InstallGenerator < Rails::Generators::Base
|
6
|
-
argument :redis_host, :type => :string, :default => "localhost", :desc => "The hostname your redis server is running on."
|
7
|
-
argument :redis_port, :type => :string, :default => "6379", :desc => "The port your redis server is running on."
|
8
|
-
class_option :redis_socket, :type => :string, :desc => "Indicates the UNIX socket your redis server is running on (if it is)."
|
9
|
-
class_option :no_migrate, :type => :boolean, :default => false, :desc => "Skip migrations. The Like and Dislike tables will not be created."
|
10
|
-
|
11
|
-
source_root File.expand_path("../templates", __FILE__)
|
12
|
-
|
13
|
-
def add_recommendable_initializer
|
14
|
-
path = "#{Rails.root}/config/initializers/recommendable.rb"
|
15
|
-
if File.exists?(path)
|
16
|
-
puts "Skipping config/initializers/recommendable.rb creation; file already exists!"
|
17
|
-
else
|
18
|
-
puts "Adding Recommendable initializer (config/initializers/recommendable.rb)"
|
19
|
-
template "initializer.rb", path
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def install_migrations
|
24
|
-
puts "Copying migrations..."
|
25
|
-
Dir.chdir(Rails.root) { puts `rake recommendable:install:migrations` }
|
26
|
-
end
|
27
|
-
|
28
|
-
def run_migrations
|
29
|
-
unless options[:no_migrate]
|
30
|
-
puts "Running rake db:migrate"
|
31
|
-
puts `rake db:migrate`
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def finished
|
36
|
-
puts "Done! Recommendable has been successfully installed. Please configure it in config/intializers/recommendable.rb"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require "redis"
|
2
|
-
|
3
|
-
# Recommendable requires a connection to a running redis-server. Either create
|
4
|
-
# a new instance based on a host/port or UNIX socket, or pass in an existing
|
5
|
-
# Redis client instance.
|
6
|
-
<% if options.redis_socket %># <% end %>Recommendable.redis = Redis.new(:host => "<%= redis_host %>", :port => <%= redis_port %>)
|
7
|
-
|
8
|
-
# Connect to Redis via a UNIX socket instead
|
9
|
-
<% unless options.redis_socket %># <% end %>Recommendable.redis = Redis.new(:sock => "<%= options.redis_socket %>")
|
10
|
-
|
11
|
-
# Tell Redis which database to use (usually between 0 and 15). The default of 0
|
12
|
-
# is most likely okay unless you have another application using that database.
|
13
|
-
# Recommendable.redis.select "0"
|
14
|
-
|
15
|
-
# If using Sidekiq, uncomment the following or place it in config/initializers/sidekiq.rb:
|
16
|
-
# Sidekiq.configure_server do |config|
|
17
|
-
# require 'sidekiq/middleware/server/unique_jobs'
|
18
|
-
# config.server_middleware do |chain|
|
19
|
-
# chain.add Sidekiq::Middleware::Server::UniqueJobs
|
20
|
-
# end
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# Sidekiq.configure_client do |config|
|
24
|
-
# require 'sidekiq/middleware/client/unique_jobs'
|
25
|
-
# config.client_middleware do |chain|
|
26
|
-
# chain.add Sidekiq::Middleware::Client::UniqueJobs
|
27
|
-
# end
|
28
|
-
# end
|
@@ -1,176 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
module ActsAsRecommendable
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
module ClassMethods
|
6
|
-
def acts_as_recommendable
|
7
|
-
class_eval do
|
8
|
-
Recommendable.recommendable_classes << self
|
9
|
-
|
10
|
-
has_many :recommendable_likes, :as => :likeable, :dependent => :destroy,
|
11
|
-
:class_name => "Recommendable::Like"
|
12
|
-
has_many :recommendable_dislikes, :as => :dislikeable, :dependent => :destroy,
|
13
|
-
:class_name => "Recommendable::Dislike"
|
14
|
-
has_many :recommendable_ignores, :as => :ignorable, :dependent => :destroy,
|
15
|
-
:class_name => "Recommendable::Ignore"
|
16
|
-
has_many :recommendable_stashes, :as => :stashable, :dependent => :destroy,
|
17
|
-
:class_name => "Recommendable::Stash"
|
18
|
-
|
19
|
-
has_many :liked_by, :through => :recommendable_likes, :source => :user,
|
20
|
-
:foreign_key => :user_id, :class_name => Recommendable.user_class.to_s
|
21
|
-
has_many :disliked_by, :through => :recommendable_dislikes, :source => :user,
|
22
|
-
:foreign_key => :user_id, :class_name => Recommendable.user_class.to_s
|
23
|
-
|
24
|
-
include LikeableMethods
|
25
|
-
include DislikeableMethods
|
26
|
-
|
27
|
-
before_destroy :remove_from_scores, :remove_from_recommendations
|
28
|
-
|
29
|
-
def self.acts_as_recommendable?() true end
|
30
|
-
|
31
|
-
def been_rated?
|
32
|
-
recommendable_likes.count + recommendable_dislikes.count > 0
|
33
|
-
end
|
34
|
-
|
35
|
-
# Returns an array of users that have liked or disliked this item.
|
36
|
-
# @return [Array] an array of users
|
37
|
-
def rated_by
|
38
|
-
liked_by + disliked_by
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.top count = 1
|
42
|
-
ids = Recommendable.redis.zrevrange(self.score_set, 0, count - 1).map(&:to_i)
|
43
|
-
|
44
|
-
items = self.find ids
|
45
|
-
return items.first if count == 1
|
46
|
-
|
47
|
-
return items.sort_by { |item| ids.index(item.id) }
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def update_score
|
53
|
-
return 0 unless been_rated?
|
54
|
-
|
55
|
-
z = 1.96
|
56
|
-
n = recommendable_likes.count + recommendable_dislikes.count
|
57
|
-
|
58
|
-
phat = recommendable_likes.count / n.to_f
|
59
|
-
score = (phat + z*z/(2*n) - z * Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n)
|
60
|
-
|
61
|
-
Recommendable.redis.zadd self.class.score_set, score, self.id
|
62
|
-
true
|
63
|
-
end
|
64
|
-
|
65
|
-
def remove_from_scores
|
66
|
-
Recommendable.redis.zrem self.class.score_set, self.id
|
67
|
-
true
|
68
|
-
end
|
69
|
-
|
70
|
-
def remove_from_recommendations
|
71
|
-
Recommendable.user_class.find_each do |user|
|
72
|
-
user.send :completely_unrecommend, self
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Used for setup purposes. Calls convenience methods to create sets
|
77
|
-
# in redis of users that both like and dislike this object.
|
78
|
-
# @return [Array] an array containing the liked_by set and the disliked_by set
|
79
|
-
# @private
|
80
|
-
def create_recommendable_sets
|
81
|
-
[create_liked_by_set, create_disliked_by_set]
|
82
|
-
end
|
83
|
-
|
84
|
-
# Used for teardown purposes. Destroys the sets in redis created by
|
85
|
-
# {#create_recommendable_sets}
|
86
|
-
# @private
|
87
|
-
def destroy_recommendable_sets
|
88
|
-
Recommendable.redis.del "#{self.class.base_class}:#{id}:liked_by"
|
89
|
-
Recommendable.redis.del "#{self.class.base_class}:#{id}:disliked_by"
|
90
|
-
end
|
91
|
-
|
92
|
-
# Returns an array of IDs of users that have liked or disliked this item.
|
93
|
-
# @return [Array] an array of user IDs
|
94
|
-
# @private
|
95
|
-
def rates_by
|
96
|
-
recommendable_likes.map(&:user_id) + recommendable_dislikes.map(&:user_id)
|
97
|
-
end
|
98
|
-
|
99
|
-
def self.score_set
|
100
|
-
"#{self}:sorted"
|
101
|
-
end
|
102
|
-
|
103
|
-
private :recommendable_likes, :recommendable_dislikes,
|
104
|
-
:recommendable_ignores, :recommendable_stashes
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def acts_as_recommendable?() false end
|
109
|
-
|
110
|
-
def sti?
|
111
|
-
self.base_class != self && self.base_class.table_name == self.table_name
|
112
|
-
end
|
113
|
-
|
114
|
-
private
|
115
|
-
end
|
116
|
-
|
117
|
-
# Instance methods.
|
118
|
-
def recommendable?() self.class.acts_as_recommendable? end
|
119
|
-
|
120
|
-
def redis_key() "#{self.class.base_class}:#{id}" end
|
121
|
-
|
122
|
-
protected :redis_key
|
123
|
-
|
124
|
-
module LikeableMethods
|
125
|
-
# Retrieve the number of likes this object has received. Cached in Redis.
|
126
|
-
# @return [Fixnum] the number of times this object has been liked
|
127
|
-
def like_count
|
128
|
-
Recommendable.redis.get("#{redis_key}:like_count").to_i
|
129
|
-
end
|
130
|
-
|
131
|
-
private
|
132
|
-
|
133
|
-
# Updates the cache for how many times this object has been liked.
|
134
|
-
# @private
|
135
|
-
def update_like_count
|
136
|
-
Recommendable.redis.set "#{redis_key}:like_count", liked_by.count
|
137
|
-
end
|
138
|
-
|
139
|
-
# Used for setup purposes. Creates a set in redis containing users that
|
140
|
-
# have liked this object.
|
141
|
-
# @private
|
142
|
-
# @return [String] the key in Redis pointing to the set
|
143
|
-
def create_liked_by_set
|
144
|
-
set = "#{redis_key}:liked_by"
|
145
|
-
liked_by.each { |rater| Recommendable.redis.sadd set, rater.id }
|
146
|
-
return set
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
module DislikeableMethods
|
151
|
-
# Retrieve the number of dislikes this object has received. Cached in Redis.
|
152
|
-
# @return [Fixnum] the number of times this object has been disliked
|
153
|
-
def dislike_count
|
154
|
-
Recommendable.redis.get("#{redis_key}:dislike_count").to_i
|
155
|
-
end
|
156
|
-
|
157
|
-
private
|
158
|
-
|
159
|
-
# Updates the cache for how many times this object has been disliked.
|
160
|
-
# @private
|
161
|
-
def update_dislike_count
|
162
|
-
Recommendable.redis.set "#{redis_key}:dislike_count", disliked_by.count
|
163
|
-
end
|
164
|
-
|
165
|
-
# Used for setup purposes. Creates a set in redis containing users that
|
166
|
-
# have disliked this object.
|
167
|
-
# @private
|
168
|
-
# @return [String] the key in Redis pointing to the set
|
169
|
-
def create_disliked_by_set
|
170
|
-
set = "#{redis_key}:disliked_by"
|
171
|
-
disliked_by.each { |rater| Recommendable.redis.sadd set, rater.id }
|
172
|
-
return set
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|