diff --git a/app/models/profile_suggestion.rb b/app/models/profile_suggestion.rb index cc57447..978adb0 100644 --- a/app/models/profile_suggestion.rb +++ b/app/models/profile_suggestion.rb @@ -8,6 +8,10 @@ class ProfileSuggestion < ActiveRecord::Base profile_suggestion.suggestion_type = self.suggestion.class.to_s end + after_destroy do |profile_suggestion| + self.class.generate_profile_suggestions(profile_suggestion.person) + end + acts_as_having_settings :field => :categories validate :must_be_a_valid_category, :on => :create @@ -50,11 +54,11 @@ class ProfileSuggestion < ActiveRecord::Base communities_with_common_tags ] - # Number of suggestions - N_SUGGESTIONS = 30 + # Number of suggestions by rule + SUGGESTIONS_BY_RULE = 10 - # Number max of attempts - MAX_ATTEMPTS = N_SUGGESTIONS * 2 + # Minimum number of suggestions + MIN_LIMIT = 15 # Number of friends in common COMMON_FRIENDS = 2 @@ -66,8 +70,12 @@ class ProfileSuggestion < ActiveRecord::Base COMMON_TAGS = 2 def self.register_suggestions(person, suggested_profiles, rule) + already_suggested_profiles = person.profile_suggestions.map(&:suggestion_id).join(',') + suggested_profiles = suggested_profiles.where("profiles.id NOT IN (#{already_suggested_profiles})") if already_suggested_profiles.present? + suggested_profiles = suggested_profiles.limit(SUGGESTIONS_BY_RULE) + return if suggested_profiles.blank? counter = rule.split(/.*_with_/).last - suggested_profiles.find_each do |suggested_profile| + suggested_profiles.each do |suggested_profile| suggestion = person.profile_suggestions.find_or_initialize_by_suggestion_id(suggested_profile.id) suggestion.send(counter+'=', suggested_profile.common_count.to_i) suggestion.save! @@ -87,6 +95,7 @@ class ProfileSuggestion < ActiveRecord::Base def self.people_with_common_friends(person) person_friends = person.friends.map(&:id) + return [] if person_friends.blank? person.environment.people. select("profiles.*, suggestions.count AS common_count"). joins(" @@ -100,6 +109,7 @@ class ProfileSuggestion < ActiveRecord::Base def self.people_with_common_communities(person) person_communities = person.communities.map(&:id) + return [] if person_communities.blank? person.environment.people. select("profiles.*, suggestions.count AS common_count"). joins(" @@ -115,6 +125,7 @@ class ProfileSuggestion < ActiveRecord::Base def self.people_with_common_tags(person) profile_tags = person.articles.select('tags.id').joins(:tags).map(&:id) + return [] if profile_tags.blank? person.environment.people. select("profiles.*, suggestions.count as common_count"). joins(" @@ -132,6 +143,7 @@ class ProfileSuggestion < ActiveRecord::Base def self.communities_with_common_friends(person) person_friends = person.friends.map(&:id) + return [] if person_friends.blank? person.environment.communities. select("profiles.*, suggestions.count AS common_count"). joins(" @@ -147,6 +159,7 @@ class ProfileSuggestion < ActiveRecord::Base def self.communities_with_common_tags(person) profile_tags = person.articles.select('tags.id').joins(:tags).map(&:id) + return [] if profile_tags.blank? person.environment.communities. select("profiles.*, suggestions.count AS common_count"). joins(" @@ -164,15 +177,17 @@ class ProfileSuggestion < ActiveRecord::Base def disable self.enabled = false - self.save + self.save! + self.class.generate_profile_suggestions(self.person) end def self.generate_all_profile_suggestions Delayed::Job.enqueue(ProfileSuggestion::GenerateAllJob.new) unless ProfileSuggestion::GenerateAllJob.exists? end - def self.generate_profile_suggestions(person_id) - Delayed::Job.enqueue ProfileSuggestionsJob.new(person_id) unless ProfileSuggestionsJob.exists?(person_id) + def self.generate_profile_suggestions(person, force = false) + return if person.profile_suggestions.enabled.count >= MIN_LIMIT && !force + Delayed::Job.enqueue ProfileSuggestionsJob.new(person.id) unless ProfileSuggestionsJob.exists?(person.id) end class GenerateAllJob @@ -181,7 +196,7 @@ class ProfileSuggestion < ActiveRecord::Base end def perform - Person.find_each {|person| ProfileSuggestion.generate_profile_suggestions(person.id) } + Person.find_each {|person| ProfileSuggestion.generate_profile_suggestions(person) } end end diff --git a/test/unit/profile_suggestion_test.rb b/test/unit/profile_suggestion_test.rb index 3d099d9..ec2471a 100644 --- a/test/unit/profile_suggestion_test.rb +++ b/test/unit/profile_suggestion_test.rb @@ -221,84 +221,136 @@ class ProfileSuggestionTest < ActiveSupport::TestCase ProfileSuggestion.calculate_suggestions(person) end - should 'update existing person suggestion when the number of common friends increase' do - suggested_person = create_user('test_user').person - suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_friends => 2) - - friend = create_user('friend').person - friend2 = create_user('friend2').person - friend3 = create_user('friend2').person - person.add_friend friend - person.add_friend friend2 - person.add_friend friend3 - - friend.add_friend suggested_person - - suggested_person.add_friend friend - suggested_person.add_friend friend2 - suggested_person.add_friend friend3 - - assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_friends(person), 'people_with_common_friends') +#FIXME This might not be necessary anymore... +# should 'update existing person suggestion when the number of common friends increase' do +# suggested_person = create_user('test_user').person +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_friends => 2) +# +# friend = create_user('friend').person +# friend2 = create_user('friend2').person +# friend3 = create_user('friend2').person +# person.add_friend friend +# person.add_friend friend2 +# person.add_friend friend3 +# +# friend.add_friend suggested_person +# +# suggested_person.add_friend friend +# suggested_person.add_friend friend2 +# suggested_person.add_friend friend3 +# +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_friends(person), 'people_with_common_friends') +# end +# end +# +# should 'update existing person suggestion when the number of common communities increase' do +# suggested_person = create_user('test_user').person +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_communities => 1) +# +# community.add_member person +# community.add_member suggested_person +# +# community2 = fast_create(Community) +# community2.add_member person +# community2.add_member suggested_person +# +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_communities', 1 do +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_communities(person), 'people_with_common_communities') +# end +# end +# +# should 'update existing person suggestion when the number of common tags increase' do +# suggested_person = create_user('test_user').person +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_tags => 1) +# +# create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') +# create(Article, :created_by => suggested_person, :profile => suggested_person, :tag_list => 'first-tag, second-tag, third-tag') +# +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_tags(person), 'people_with_common_tags') +# end +# end +# +# should 'update existing community suggestion when the number of common friends increase' do +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_friends => 1) +# +# member1 = create_user('member1').person +# member2 = create_user('member2').person +# +# person.add_friend member1 +# person.add_friend member2 +# +# community.add_member member1 +# community.add_member member2 +# +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_friends(person), 'communities_with_common_friends') +# end +# +# end +# +# should 'update existing community suggestion when the number of common tags increase' do +# other_person = create_user('test_user').person +# +# suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_tags => 1) +# +# create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') +# create(Article, :created_by => other_person, :profile => community, :tag_list => 'first-tag, second-tag, third-tag') +# +# assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do +# ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_tags(person), 'communities_with_common_tags') +# end +# end + + should 'register only new suggestions' do + person = create_user('person').person + ProfileSuggestion::SUGGESTIONS_BY_RULE.times do + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Person)) end - end - should 'update existing person suggestion when the number of common communities increase' do - suggested_person = create_user('test_user').person - suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_communities => 1) + person.reload + new_suggestion = fast_create(Person) + ids = (person.suggested_people + [new_suggestion]).map(&:id).join(',') + suggested_profiles = Profile.select('profiles.*, profiles.id as common_count').where("profiles.id IN (#{ids})") - community.add_member person - community.add_member suggested_person - - community2 = fast_create(Community) - community2.add_member person - community2.add_member suggested_person - - assert_difference 'ProfileSuggestion.find(suggestion.id).common_communities', 1 do - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_communities(person), 'people_with_common_communities') + assert_difference 'ProfileSuggestion.count', 1 do + ProfileSuggestion.register_suggestions(person, suggested_profiles, 'people_with_common_friends') end end - should 'update existing person suggestion when the number of common tags increase' do - suggested_person = create_user('test_user').person - suggestion = ProfileSuggestion.create(:person => person, :suggestion => suggested_person, :common_tags => 1) - - create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') - create(Article, :created_by => suggested_person, :profile => suggested_person, :tag_list => 'first-tag, second-tag, third-tag') - - assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.people_with_common_tags(person), 'people_with_common_tags') + should 'calculate new suggestions when number of available suggestions reaches the min_limit' do + person = create_user('person').person + (ProfileSuggestion::MIN_LIMIT + 1).times do + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Profile)) end - end - - should 'update existing community suggestion when the number of common friends increase' do - suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_friends => 1) - - member1 = create_user('member1').person - member2 = create_user('member2').person - person.add_friend member1 - person.add_friend member2 + ProfileSuggestion.expects(:calculate_suggestions) - community.add_member member1 - community.add_member member2 + person.profile_suggestions.enabled.last.disable + person.profile_suggestions.enabled.last.destroy + process_delayed_job_queue + end - assert_difference 'ProfileSuggestion.find(suggestion.id).common_friends', 1 do - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_friends(person), 'communities_with_common_friends') + should 'not create job to calculate new suggestions if there is already enough suggestions enabled' do + person = create_user('person').person + (ProfileSuggestion::MIN_LIMIT + 1).times do + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Profile)) end + ProfileSuggestion.expects(:calculate_suggestions).never + ProfileSuggestion.generate_profile_suggestions(person) + process_delayed_job_queue end - should 'update existing community suggestion when the number of common tags increase' do - other_person = create_user('test_user').person - - suggestion = ProfileSuggestion.create(:person => person, :suggestion => community, :common_tags => 1) - - create(Article, :created_by => person, :profile => person, :tag_list => 'first-tag, second-tag, third-tag, fourth-tag') - create(Article, :created_by => other_person, :profile => community, :tag_list => 'first-tag, second-tag, third-tag') - - assert_difference 'ProfileSuggestion.find(suggestion.id).common_tags', 2 do - ProfileSuggestion.register_suggestions(person, ProfileSuggestion.communities_with_common_tags(person), 'communities_with_common_tags') + should 'be able to force suggestions calculation' do + person = create_user('person').person + (ProfileSuggestion::MIN_LIMIT + 1).times do + ProfileSuggestion.create!(:person => person, :suggestion => fast_create(Profile)) end + + ProfileSuggestion.expects(:calculate_suggestions) + ProfileSuggestion.generate_profile_suggestions(person, true) + process_delayed_job_queue end end -- libgit2 0.21.2