Commit 8eb914c0811e0235b9ae926f712061785ca40c06
1 parent
5fba93dd
Exists in
master
and in
28 other branches
action_tracker: register and use activities_count to fetch most_active profile
(ActionItem3039)
Showing
10 changed files
with
158 additions
and
64 deletions
Show diff stats
app/models/organization.rb
... | ... | @@ -32,13 +32,6 @@ class Organization < Profile |
32 | 32 | :joins => "LEFT OUTER JOIN role_assignments ON profiles.id = role_assignments.resource_id", |
33 | 33 | :order => "total DESC" |
34 | 34 | |
35 | - named_scope :more_active, | |
36 | - :select => "#{Profile.qualified_column_names}, count(action_tracker.id) as total", | |
37 | - :joins => "LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.target_id", | |
38 | - :group => Profile.qualified_column_names, | |
39 | - :order => 'total DESC', | |
40 | - :conditions => ['action_tracker.created_at >= ? OR action_tracker.id IS NULL', ActionTracker::Record::RECENT_DELAY.days.ago] | |
41 | - | |
42 | 35 | def validation_methodology |
43 | 36 | self.validation_info ? self.validation_info.validation_methodology : nil |
44 | 37 | end | ... | ... |
app/models/person.rb
... | ... | @@ -68,13 +68,6 @@ class Person < Profile |
68 | 68 | |
69 | 69 | named_scope :more_popular, :order => 'friends_count DESC' |
70 | 70 | |
71 | - named_scope :more_active, | |
72 | - :select => "#{Profile.qualified_column_names}, count(action_tracker.id) as total", | |
73 | - :joins => "LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.user_id", | |
74 | - :group => Profile.qualified_column_names, | |
75 | - :order => 'total DESC', | |
76 | - :conditions => ['action_tracker.created_at >= ? OR action_tracker.id IS NULL', ActionTracker::Record::RECENT_DELAY.days.ago] | |
77 | - | |
78 | 71 | named_scope :abusers, :joins => :abuse_complaints, :conditions => ['tasks.status = 3'], :select => 'DISTINCT profiles.*' |
79 | 72 | named_scope :non_abusers, :joins => "LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'", :conditions => ["tasks.status != 3 OR tasks.id is NULL"], :select => "DISTINCT profiles.*" |
80 | 73 | ... | ... |
app/models/profile.rb
... | ... | @@ -113,10 +113,11 @@ class Profile < ActiveRecord::Base |
113 | 113 | |
114 | 114 | named_scope :visible, :conditions => { :visible => true } |
115 | 115 | named_scope :public, :conditions => { :visible => true, :public_profile => true } |
116 | - # Subclasses must override these methods | |
116 | + | |
117 | + # Subclasses must override this method | |
117 | 118 | named_scope :more_popular |
118 | - named_scope :more_active | |
119 | 119 | |
120 | + named_scope :more_active, :order => 'activities_count DESC' | |
120 | 121 | named_scope :more_recent, :order => "created_at DESC" |
121 | 122 | |
122 | 123 | acts_as_trackable :dependent => :destroy | ... | ... |
db/migrate/20140312151857_define_initial_value_for_profiles_activities_count.rb
0 → 100644
... | ... | @@ -0,0 +1,14 @@ |
1 | +class DefineInitialValueForProfilesActivitiesCount < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + person_activities_counts = execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.user_id WHERE (action_tracker.created_at >= '#{30.days.ago.to_s(:db)}') AND ( (profiles.type = 'Person' ) ) GROUP BY profiles.id;") | |
4 | + organization_activities_counts = execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.target_id WHERE (action_tracker.created_at >= '#{30.days.ago.to_s(:db)}') AND ( (profiles.type = 'Community' OR profiles.type = 'Enterprise' OR profiles.type = 'Organization' ) ) GROUP BY profiles.id;") | |
5 | + activities_counts = person_activities_counts.entries + organization_activities_counts.entries | |
6 | + activities_counts.each do |count| | |
7 | + execute("UPDATE profiles SET activities_count=#{count['count'].to_i} WHERE profiles.id=#{count['id']};") | |
8 | + end | |
9 | + end | |
10 | + | |
11 | + def self.down | |
12 | + execute("UPDATE profiles SET activities_count=0;") | |
13 | + end | |
14 | +end | ... | ... |
... | ... | @@ -0,0 +1,11 @@ |
1 | +class ActivitiesCounterCacheJob | |
2 | + def perform | |
3 | + person_activities_counts = ActiveRecord::Base.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.user_id WHERE (action_tracker.created_at >= '#{ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db)}') AND ( (profiles.type = 'Person' ) ) GROUP BY profiles.id;") | |
4 | + organization_activities_counts = ActiveRecord::Base.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.target_id WHERE (action_tracker.created_at >= '#{ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db)}') AND ( (profiles.type = 'Community' OR profiles.type = 'Enterprise' OR profiles.type = 'Organization' ) ) GROUP BY profiles.id;") | |
5 | + activities_counts = person_activities_counts.entries + organization_activities_counts.entries | |
6 | + activities_counts.each do |count| | |
7 | + ActiveRecord::Base.connection.execute("UPDATE profiles SET activities_count=#{count['count'].to_i} WHERE profiles.id=#{count['id']};") | |
8 | + end | |
9 | + Delayed::Job.enqueue(ActivitiesCounterCacheJob.new, -3, 1.day.from_now) | |
10 | + end | |
11 | +end | ... | ... |
... | ... | @@ -0,0 +1,34 @@ |
1 | +require File.dirname(__FILE__) + '/../test_helper' | |
2 | + | |
3 | +class ActivitiesCounterCacheJobTest < ActiveSupport::TestCase | |
4 | + | |
5 | + should 'correctly update the person activities counter cache' do | |
6 | + person = create_user('person').person | |
7 | + ActionTracker::Record.create!(:user => person, :verb => 'create_article') | |
8 | + ActionTracker::Record.create!(:user => person, :verb => 'create_article') | |
9 | + assert_equal 2, person.activities_count | |
10 | + | |
11 | + person.activities_count = 0 | |
12 | + person.save! | |
13 | + job = ActivitiesCounterCacheJob.new | |
14 | + job.perform | |
15 | + person.reload | |
16 | + assert_equal 2, person.activities_count | |
17 | + end | |
18 | + | |
19 | + should 'correctly update the organization activities counter cache' do | |
20 | + person = create_user('person').person | |
21 | + organization = Organization.create!(:name => 'Organization1', :identifier => 'organization1') | |
22 | + ActionTracker::Record.create!(:user => person, :verb => 'create_article', :target => organization) | |
23 | + ActionTracker::Record.create!(:user => person, :verb => 'create_article', :target => organization) | |
24 | + assert_equal 2, organization.activities_count | |
25 | + | |
26 | + organization.activities_count = 0 | |
27 | + organization.save! | |
28 | + job = ActivitiesCounterCacheJob.new | |
29 | + job.perform | |
30 | + organization.reload | |
31 | + assert_equal 2, organization.activities_count | |
32 | + end | |
33 | + | |
34 | +end | ... | ... |
test/unit/organization_test.rb
... | ... | @@ -364,25 +364,7 @@ class OrganizationTest < ActiveSupport::TestCase |
364 | 364 | fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person, :created_at => Time.now, :target_id => p3.id) |
365 | 365 | fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person, :created_at => Time.now, :target_id => p3.id) |
366 | 366 | |
367 | - assert_equal [p3,p2,p1] , Organization.more_active | |
368 | - end | |
369 | - | |
370 | - should 'more active profile take in consideration only actions created only in the recent delay interval' do | |
371 | - ActionTracker::Record.destroy_all | |
372 | - recent_delay = ActionTracker::Record::RECENT_DELAY.days.ago | |
373 | - | |
374 | - person = fast_create(Person) | |
375 | - Organization.destroy_all | |
376 | - p1 = fast_create(Organization) | |
377 | - p2 = fast_create(Organization) | |
378 | - | |
379 | - ActionTracker::Record.destroy_all | |
380 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person, :created_at => recent_delay, :target_id => p1.id) | |
381 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person, :created_at => recent_delay, :target_id => p1.id) | |
382 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person, :created_at => recent_delay, :target_id => p2.id) | |
383 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person, :created_at => recent_delay - 1.day, :target_id => p2.id) | |
384 | - | |
385 | - assert_equal [p1,p2] , Organization.more_active | |
367 | + assert_order [p3,p2,p1] , Organization.more_active | |
386 | 368 | end |
387 | 369 | |
388 | 370 | should 'list profiles that have no actions in more active list' do |
... | ... | @@ -422,4 +404,34 @@ class OrganizationTest < ActiveSupport::TestCase |
422 | 404 | assert !organization.visible |
423 | 405 | end |
424 | 406 | |
407 | + should 'increase activities_count on new activity' do | |
408 | + person = fast_create(Person) | |
409 | + organization = fast_create(Organization) | |
410 | + assert_difference organization, :activities_count, 1 do | |
411 | + ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => organization | |
412 | + organization.reload | |
413 | + end | |
414 | + end | |
415 | + | |
416 | + should 'decrease activities_count on activity removal' do | |
417 | + person = fast_create(Person) | |
418 | + organization = fast_create(Organization) | |
419 | + record = ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => organization | |
420 | + assert_difference organization, :activities_count, -1 do | |
421 | + record.destroy | |
422 | + organization.reload | |
423 | + end | |
424 | + end | |
425 | + | |
426 | + should 'not decrease activities_count on activity removal after the recent delay' do | |
427 | + person = fast_create(Person) | |
428 | + organization = fast_create(Organization) | |
429 | + record = ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => organization, :created_at => (ActionTracker::Record::RECENT_DELAY + 1).days.ago | |
430 | + assert_no_difference organization, :activities_count do | |
431 | + record.destroy | |
432 | + organization.reload | |
433 | + end | |
434 | + end | |
435 | + | |
436 | + | |
425 | 437 | end | ... | ... |
test/unit/person_test.rb
... | ... | @@ -904,14 +904,15 @@ class PersonTest < ActiveSupport::TestCase |
904 | 904 | |
905 | 905 | action_tracker = fast_create(ActionTracker::Record, :verb => 'create_article') |
906 | 906 | action_tracker.target = community |
907 | + action_tracker.user = p4 | |
907 | 908 | action_tracker.save! |
908 | 909 | ActionTrackerNotification.delete_all |
909 | - assert_difference(ActionTrackerNotification, :count, 3) do | |
910 | + assert_difference(ActionTrackerNotification, :count, 4) do | |
910 | 911 | Person.notify_activity(action_tracker) |
911 | 912 | process_delayed_job_queue |
912 | 913 | end |
913 | 914 | ActionTrackerNotification.all.map{|a|a.profile}.map do |profile| |
914 | - assert [community,p1,p3].include?(profile) | |
915 | + assert [community,p1,p3,p4].include?(profile) | |
915 | 916 | end |
916 | 917 | end |
917 | 918 | |
... | ... | @@ -1014,9 +1015,9 @@ class PersonTest < ActiveSupport::TestCase |
1014 | 1015 | |
1015 | 1016 | should 'the community specific notification created when a member joins community could not be propagated to members' do |
1016 | 1017 | ActionTracker::Record.delete_all |
1017 | - p1 = create_user('test_user').person | |
1018 | - p2 = create_user('test_user').person | |
1019 | - p3 = create_user('test_user').person | |
1018 | + p1 = create_user('p1').person | |
1019 | + p2 = create_user('p2').person | |
1020 | + p3 = create_user('p3').person | |
1020 | 1021 | c = fast_create(Community, :name => "Foo") |
1021 | 1022 | c.add_member(p1) |
1022 | 1023 | process_delayed_job_queue |
... | ... | @@ -1136,30 +1137,14 @@ class PersonTest < ActiveSupport::TestCase |
1136 | 1137 | p3 = fast_create(Person) |
1137 | 1138 | |
1138 | 1139 | ActionTracker::Record.destroy_all |
1139 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p1, :created_at => Time.now) | |
1140 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p2, :created_at => Time.now) | |
1141 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p2, :created_at => Time.now) | |
1142 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p3, :created_at => Time.now) | |
1143 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p3, :created_at => Time.now) | |
1144 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p3, :created_at => Time.now) | |
1145 | - | |
1146 | - assert_equal [p3,p2,p1] , Person.more_active | |
1147 | - end | |
1148 | - | |
1149 | - should 'more active profile take in consideration only actions created only in the recent delay interval' do | |
1150 | - Person.delete_all | |
1151 | - ActionTracker::Record.destroy_all | |
1152 | - recent_delay = ActionTracker::Record::RECENT_DELAY.days.ago | |
1140 | + fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p1) | |
1141 | + fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p2) | |
1142 | + fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p2) | |
1143 | + fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p3) | |
1144 | + fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p3) | |
1145 | + fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p3) | |
1153 | 1146 | |
1154 | - p1 = fast_create(Person) | |
1155 | - p2 = fast_create(Person) | |
1156 | - | |
1157 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p1, :created_at => recent_delay) | |
1158 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p1, :created_at => recent_delay) | |
1159 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p2, :created_at => recent_delay) | |
1160 | - fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => p2, :created_at => recent_delay - 1.day) | |
1161 | - | |
1162 | - assert_equal [p1,p2], Person.more_active | |
1147 | + assert_order [p3,p2,p1] , Person.more_active | |
1163 | 1148 | end |
1164 | 1149 | |
1165 | 1150 | should 'list profiles that have no actions in more active list' do |
... | ... | @@ -1429,7 +1414,7 @@ class PersonTest < ActiveSupport::TestCase |
1429 | 1414 | end |
1430 | 1415 | end |
1431 | 1416 | |
1432 | - should 'decrease friends_count on new friendship' do | |
1417 | + should 'decrease friends_count on friendship removal' do | |
1433 | 1418 | person = create_user('person').person |
1434 | 1419 | friend = create_user('friend').person |
1435 | 1420 | person.add_friend(friend) |
... | ... | @@ -1443,4 +1428,33 @@ class PersonTest < ActiveSupport::TestCase |
1443 | 1428 | person.reload |
1444 | 1429 | end |
1445 | 1430 | end |
1431 | + | |
1432 | + should 'increase activities_count on new activity' do | |
1433 | + person = fast_create(Person) | |
1434 | + assert_difference person, :activities_count, 1 do | |
1435 | + ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => fast_create(Profile) | |
1436 | + person.reload | |
1437 | + end | |
1438 | + end | |
1439 | + | |
1440 | + should 'decrease activities_count on activity removal' do | |
1441 | + person = fast_create(Person) | |
1442 | + record = ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => fast_create(Profile) | |
1443 | + assert_difference person, :activities_count, -1 do | |
1444 | + record.destroy | |
1445 | + person.reload | |
1446 | + end | |
1447 | + end | |
1448 | + | |
1449 | + should 'not decrease activities_count on activity removal after the recent delay' do | |
1450 | + person = fast_create(Person) | |
1451 | + record = ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => fast_create(Profile) | |
1452 | + record.created_at = record.created_at - ActionTracker::Record::RECENT_DELAY.days - 1.day | |
1453 | + record.save! | |
1454 | + assert_no_difference person, :activities_count do | |
1455 | + record.destroy | |
1456 | + person.reload | |
1457 | + end | |
1458 | + end | |
1459 | + | |
1446 | 1460 | end | ... | ... |
vendor/plugins/action_tracker/lib/action_tracker_model.rb
1 | 1 | module ActionTracker |
2 | 2 | class Record < ActiveRecord::Base |
3 | 3 | |
4 | + extend CacheCounterHelper | |
5 | + | |
4 | 6 | set_table_name 'action_tracker' |
5 | 7 | |
6 | 8 | belongs_to :user, :polymorphic => true |
... | ... | @@ -14,6 +16,22 @@ module ActionTracker |
14 | 16 | validates_presence_of :user |
15 | 17 | validate :user_existence |
16 | 18 | |
19 | + after_create do |record| | |
20 | + update_cache_counter(:activities_count, record.user, 1) | |
21 | + if record.target.kind_of?(Organization) | |
22 | + update_cache_counter(:activities_count, record.target, 1) | |
23 | + end | |
24 | + end | |
25 | + | |
26 | + after_destroy do |record| | |
27 | + if record.created_at >= RECENT_DELAY.days.ago | |
28 | + update_cache_counter(:activities_count, record.user, -1) | |
29 | + if record.target.kind_of?(Organization) | |
30 | + update_cache_counter(:activities_count, record.target, -1) | |
31 | + end | |
32 | + end | |
33 | + end | |
34 | + | |
17 | 35 | def user_existence |
18 | 36 | errors.add(:user, "user doesn't exists") if user && !user.class.exists?(user) |
19 | 37 | end | ... | ... |