Module: Recommendable::ActsAsRecommendable::ClassMethods

Defined in:
lib/recommendable/acts_as_recommendable.rb

Instance Method Summary collapse

Instance Method Details

#acts_as_recommendableObject



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/recommendable/acts_as_recommendable.rb', line 6

def acts_as_recommendable
  class_eval do
    Recommendable.recommendable_classes << self
    
    has_many :recommendable_likes, :as => :likeable, :dependent => :destroy,
                                   :class_name => "Recommendable::Like"
    has_many :recommendable_dislikes, :as => :dislikeable, :dependent => :destroy,
                                      :class_name => "Recommendable::Dislike"
    has_many :recommendable_ignores, :as => :ignorable, :dependent => :destroy,
                                     :class_name => "Recommendable::Ignore"
    has_many :recommendable_stashes, :as => :stashable, :dependent => :destroy,
                                     :class_name => "Recommendable::Stash"

    has_many :liked_by, :through => :recommendable_likes, :source => :user,
                        :foreign_key => :user_id, :class_name => Recommendable.user_class.to_s
    has_many :disliked_by, :through => :recommendable_dislikes, :source => :user,
                           :foreign_key => :user_id, :class_name => Recommendable.user_class.to_s
    
    include LikeableMethods
    include DislikeableMethods

    before_destroy :remove_from_scores, :remove_from_recommendations
    
    def self.acts_as_recommendable?() true end

    def been_rated?
      recommendable_likes.count + recommendable_dislikes.count > 0
    end

    # Returns an array of users that have liked or disliked this item.
    # @return [Array] an array of users
    def rated_by
      liked_by + disliked_by
    end

    def self.top count = 1
      ids = Recommendable.redis.zrevrange(self.score_set, 0, count - 1).map(&:to_i)

      items = self.find ids
      return items.first if count == 1

      return items.sort { |x, y| ids.index(x.id) <=> ids.index(y.id) }
    end

    private

    def update_score
      return 0 unless been_rated?

      z = 1.96
      n = recommendable_likes.count + recommendable_dislikes.count

      phat = recommendable_likes.count / n.to_f
      score = (phat + z*z/(2*n) - z * Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n)

      Recommendable.redis.zadd self.class.score_set, score, self.id
      true
    end

    def remove_from_scores
      Recommendable.redis.zrem self.class.score_set, self.id
      true
    end

    def remove_from_recommendations
      Recommendable.user_class.find_each do |user|
        user.send :completely_unrecommend, self
      end
    end
    
    # Used for setup purposes. Calls convenience methods to create sets
    # in redis of users that both like and dislike this object.
    # @return [Array] an array containing the liked_by set and the disliked_by set
    # @private
    def create_recommendable_sets
      [create_liked_by_set, create_disliked_by_set]
    end
    
    # Used for teardown purposes. Destroys the sets in redis created by
    # {#create_recommendable_sets}
    # @private
    def destroy_recommendable_sets
      Recommendable.redis.del "#{self.class.base_class}:#{id}:liked_by"
      Recommendable.redis.del "#{self.class.base_class}:#{id}:disliked_by"
    end

    # Returns an array of IDs of users that have liked or disliked this item.
    # @return [Array] an array of user IDs
    # @private
    def rates_by
      recommendable_likes.map(&:user_id) + recommendable_dislikes.map(&:user_id)
    end

    def self.score_set
      "#{self}:sorted"
    end

    private :recommendable_likes, :recommendable_dislikes,
            :recommendable_ignores, :recommendable_stashes
  end
end

#acts_as_recommendable?Boolean

Returns:

  • (Boolean)


108
# File 'lib/recommendable/acts_as_recommendable.rb', line 108

def acts_as_recommendable?() false end

#sti?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/recommendable/acts_as_recommendable.rb', line 110

def sti?
  self.base_class != self && self.base_class.table_name == self.table_name
end