diff --git a/Gemfile b/Gemfile index 8645810dec1..136b9248836 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,6 @@ end if rails_master? gem 'arel', git: 'https://github.com/rails/arel.git' gem 'rails', git: 'https://github.com/rails/rails.git' - gem 'rails-observers', git: 'https://github.com/rails/rails-observers.git' gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse' else # Rails 5 is going to ship with Action Cable, we have no use for it as @@ -29,8 +28,6 @@ else # gem 'railties' # gem 'sprockets-rails' gem 'rails', '~> 4.2' - - gem 'rails-observers' gem 'seed-fu', '~> 2.3.5' end diff --git a/Gemfile.lock b/Gemfile.lock index 9e8873ade36..3b1931ca3c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -260,8 +260,6 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - rails-observers (0.1.2) - activemodel (~> 4.0) rails_multisite (1.0.6) rails (> 4.2, < 5) railties (4.2.7.1) @@ -453,7 +451,6 @@ DEPENDENCIES rack-mini-profiler rack-protection rails (~> 4.2) - rails-observers rails_multisite rake rb-fsevent diff --git a/app/models/anon_site_json_cache_observer.rb b/app/models/anon_site_json_cache_observer.rb deleted file mode 100644 index cacb0d1431e..00000000000 --- a/app/models/anon_site_json_cache_observer.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AnonSiteJsonCacheObserver < ActiveRecord::Observer - observe :category, :post_action_type, :user_field, :group - - def after_destroy(object) - Site.clear_anon_cache! - end - - def after_save(object) - Site.clear_anon_cache! - end - -end diff --git a/app/models/category.rb b/app/models/category.rb index c4278b38870..62b22a11954 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -6,6 +6,7 @@ class Category < ActiveRecord::Base include Positionable include HasCustomFields include CategoryHashtag + include AnonCacheInvalidator belongs_to :topic, dependent: :destroy belongs_to :topic_only_relative_url, diff --git a/app/models/concerns/anon_cache_invalidator.rb b/app/models/concerns/anon_cache_invalidator.rb new file mode 100644 index 00000000000..ac37eb69450 --- /dev/null +++ b/app/models/concerns/anon_cache_invalidator.rb @@ -0,0 +1,13 @@ +module AnonCacheInvalidator + extend ActiveSupport::Concern + + included do + after_destroy do + Site.clear_anon_cache! + end + + after_save do + Site.clear_anon_cache! + end + end +end diff --git a/app/models/group.rb b/app/models/group.rb index d1fbf372e28..b97c34356c5 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -1,5 +1,6 @@ class Group < ActiveRecord::Base include HasCustomFields + include AnonCacheInvalidator has_many :category_groups, dependent: :destroy has_many :group_users, dependent: :destroy diff --git a/app/models/post_action.rb b/app/models/post_action.rb index fb63edbf0c4..e90767a087c 100644 --- a/app/models/post_action.rb +++ b/app/models/post_action.rb @@ -23,6 +23,8 @@ class PostAction < ActiveRecord::Base after_save :update_counters after_save :enforce_rules after_save :create_user_action + after_save :update_notifications + after_create :create_notifications after_commit :notify_subscribers def disposed_by_id @@ -281,7 +283,7 @@ SQL post_action.recover! action_attrs.each { |attr, val| post_action.send("#{attr}=", val) } post_action.save - PostAlertObserver.after_create_post_action(post_action) + PostActionNotifier.post_action_created(post_action) else post_action = create(where_attrs.merge(action_attrs)) if post_action && post_action.errors.count == 0 @@ -460,6 +462,16 @@ SQL end end + def update_notifications + if self.deleted_at.present? + PostActionNotifier.post_action_deleted(self) + end + end + + def create_notifications + PostActionNotifier.post_action_created(self) + end + def notify_subscribers if (is_like? || is_flag?) && post post.publish_change_to_clients! :acted diff --git a/app/models/post_action_type.rb b/app/models/post_action_type.rb index 48935123b03..6af07c53af6 100644 --- a/app/models/post_action_type.rb +++ b/app/models/post_action_type.rb @@ -5,6 +5,8 @@ class PostActionType < ActiveRecord::Base after_save :expire_cache after_destroy :expire_cache + include AnonCacheInvalidator + def expire_cache ApplicationSerializer.expire_cache_fragment!("post_action_types") ApplicationSerializer.expire_cache_fragment!("post_action_flag_types") diff --git a/app/models/post_revision.rb b/app/models/post_revision.rb index a11a1f35ed7..0a7016966dd 100644 --- a/app/models/post_revision.rb +++ b/app/models/post_revision.rb @@ -6,6 +6,8 @@ class PostRevision < ActiveRecord::Base serialize :modifications, Hash + after_create :create_notification + def self.ensure_consistency! # 1 - fix the numbers PostRevision.exec_sql <<-SQL @@ -34,6 +36,10 @@ class PostRevision < ActiveRecord::Base update_column(:hidden, false) end + def create_notification + PostActionNotifier.after_create_post_revision(self) + end + end # == Schema Information diff --git a/app/models/user_field.rb b/app/models/user_field.rb index 751b65755a1..6505982b9cc 100644 --- a/app/models/user_field.rb +++ b/app/models/user_field.rb @@ -1,4 +1,7 @@ class UserField < ActiveRecord::Base + + include AnonCacheInvalidator + validates_presence_of :name, :description, :field_type has_many :user_field_options, dependent: :destroy accepts_nested_attributes_for :user_field_options diff --git a/app/models/post_alert_observer.rb b/app/services/post_action_notifier.rb similarity index 73% rename from app/models/post_alert_observer.rb rename to app/services/post_action_notifier.rb index f1913ab7767..345e6aa735a 100644 --- a/app/models/post_alert_observer.rb +++ b/app/services/post_action_notifier.rb @@ -1,27 +1,18 @@ -class PostAlertObserver < ActiveRecord::Observer - observe :post_action, :post_revision +class PostActionNotifier + + def self.disable + @disabled = true + end + + def self.enable + @disabled = false + end def self.alerter @alerter ||= PostAlerter.new end - def alerter - self.class.alerter - end - - # Dispatch to an after_save_#{class_name} method - def after_save(model) - method_name = callback_for('after_save', model) - send(method_name, model) if respond_to?(method_name) - end - - # Dispatch to an after_create_#{class_name} method - def after_create(model) - method_name = callback_for('after_create', model) - send(method_name, model) if respond_to?(method_name) - end - - def refresh_like_notification(post, read) + def self.refresh_like_notification(post, read) return unless post && post.user_id usernames = post.post_actions.where(post_action_type_id: PostActionType.types[:like]) @@ -49,7 +40,10 @@ class PostAlertObserver < ActiveRecord::Observer end end - def after_save_post_action(post_action) + def self.post_action_deleted(post_action) + + return if @disabled + # We only care about deleting post actions for now return if post_action.deleted_at.blank? @@ -74,7 +68,10 @@ class PostAlertObserver < ActiveRecord::Observer end end - def self.after_create_post_action(post_action) + def self.post_action_created(post_action) + + return if @disabled + # We only notify on likes for now return unless post_action.is_like? @@ -91,11 +88,10 @@ class PostAlertObserver < ActiveRecord::Observer ) end - def after_create_post_action(post_action) - self.class.after_create_post_action(post_action) - end + def self.after_create_post_revision(post_revision) + + return if @disabled - def after_create_post_revision(post_revision) post = post_revision.post return unless post @@ -113,10 +109,4 @@ class PostAlertObserver < ActiveRecord::Observer ) end - protected - - def callback_for(action, model) - "#{action}_#{model.class.name.underscore.gsub(/.+\//, '')}" - end - end diff --git a/config/application.rb b/config/application.rb index 38dd39d7012..c098564340b 100644 --- a/config/application.rb +++ b/config/application.rb @@ -80,11 +80,6 @@ module Discourse config.assets.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}" end - # Activate observers that should always be running. - config.active_record.observers = [ - :post_alert_observer, - ] - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. config.time_zone = 'UTC' diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index c4eb2261367..6c144923947 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -5,7 +5,6 @@ require 'topic_subtype' describe PostCreator do before do - ActiveRecord::Base.observers.enable :all end let(:user) { Fabricate(:user) } diff --git a/spec/components/post_destroyer_spec.rb b/spec/components/post_destroyer_spec.rb index 05690326301..58781bd2f14 100644 --- a/spec/components/post_destroyer_spec.rb +++ b/spec/components/post_destroyer_spec.rb @@ -4,7 +4,6 @@ require 'post_destroyer' describe PostDestroyer do before do - ActiveRecord::Base.observers.enable :all UserActionCreator.enable end diff --git a/spec/controllers/user_actions_controller_spec.rb b/spec/controllers/user_actions_controller_spec.rb index c4efbfbcdaf..9e606101272 100644 --- a/spec/controllers/user_actions_controller_spec.rb +++ b/spec/controllers/user_actions_controller_spec.rb @@ -9,7 +9,6 @@ describe UserActionsController do end it 'renders list correctly' do - ActiveRecord::Base.observers.enable :all UserActionCreator.enable post = Fabricate(:post) diff --git a/spec/models/category_user_spec.rb b/spec/models/category_user_spec.rb index 3bdb11767fa..d22098ab99a 100644 --- a/spec/models/category_user_spec.rb +++ b/spec/models/category_user_spec.rb @@ -68,7 +68,6 @@ describe CategoryUser do context 'integration' do before do - ActiveRecord::Base.observers.enable :all NotificationEmailer.enable end diff --git a/spec/models/directory_item_spec.rb b/spec/models/directory_item_spec.rb index c7a0fa6efbe..37131d1bf83 100644 --- a/spec/models/directory_item_spec.rb +++ b/spec/models/directory_item_spec.rb @@ -20,7 +20,6 @@ describe DirectoryItem do context 'refresh' do before do - ActiveRecord::Base.observers.enable :all UserActionCreator.enable end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 4d00ab80e3e..02ee99917c7 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -2,7 +2,6 @@ require 'rails_helper' describe Notification do before do - ActiveRecord::Base.observers.enable :all NotificationEmailer.enable end @@ -235,7 +234,6 @@ describe Notification do describe 'ensure consistency' do it 'deletes notifications if post is missing or deleted' do - ActiveRecord::Base.observers.disable :all NotificationEmailer.disable p = Fabricate(:post) diff --git a/spec/models/post_action_spec.rb b/spec/models/post_action_spec.rb index fb621269dfb..aa7daba215e 100644 --- a/spec/models/post_action_spec.rb +++ b/spec/models/post_action_spec.rb @@ -220,7 +220,9 @@ describe PostAction do describe 'when a user likes something' do it 'should generate notifications correctly' do - ActiveRecord::Base.observers.enable :all + + PostActionNotifier.enable + PostAction.act(codinghorror, post, PostActionType.types[:like]) expect(Notification.count).to eq(1) diff --git a/spec/models/post_mover_spec.rb b/spec/models/post_mover_spec.rb index f6bd9bc7699..bb606ef791b 100644 --- a/spec/models/post_mover_spec.rb +++ b/spec/models/post_mover_spec.rb @@ -31,8 +31,6 @@ describe PostMover do before do p1.replies << p3 p2.replies << p4 - # add a like to a post, enable observers so we get user actions - ActiveRecord::Base.observers.enable :all UserActionCreator.enable @like = PostAction.act(another_user, p4, PostActionType.types[:like]) end diff --git a/spec/models/post_timing_spec.rb b/spec/models/post_timing_spec.rb index 7817cee98b9..74aec7b8e68 100644 --- a/spec/models/post_timing_spec.rb +++ b/spec/models/post_timing_spec.rb @@ -81,8 +81,7 @@ describe PostTiming do # integration test it 'processes timings correctly' do - - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post) user2 = Fabricate(:coding_horror, created_at: 1.day.ago) diff --git a/spec/models/site_spec.rb b/spec/models/site_spec.rb index a3376a4c4e9..d8bb189b343 100644 --- a/spec/models/site_spec.rb +++ b/spec/models/site_spec.rb @@ -3,9 +3,6 @@ require_dependency 'site' describe Site do it "omits categories users can not write to from the category list" do - - ActiveRecord::Base.observers.enable :anon_site_json_cache_observer - category = Fabricate(:category) user = Fabricate(:user) diff --git a/spec/models/tag_user_spec.rb b/spec/models/tag_user_spec.rb index 2e4dd4bdb04..aee8839eca0 100644 --- a/spec/models/tag_user_spec.rb +++ b/spec/models/tag_user_spec.rb @@ -68,12 +68,7 @@ describe TagUser do end context "integration" do - before do - ActiveRecord::Base.observers.enable :all - end - let(:user) { Fabricate(:user) } - let(:watched_tag) { Fabricate(:tag) } let(:muted_tag) { Fabricate(:tag) } let(:tracked_tag) { Fabricate(:tag) } diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index edeafa5a393..e4574b75c98 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -429,7 +429,6 @@ describe Topic do let(:actions) { topic.user.user_actions } it "should set up actions correctly" do - ActiveRecord::Base.observers.enable :all UserActionCreator.enable expect(actions.map{|a| a.action_type}).not_to include(UserAction::NEW_TOPIC) diff --git a/spec/models/topic_user_spec.rb b/spec/models/topic_user_spec.rb index e92e694306b..04c3c1440f0 100644 --- a/spec/models/topic_user_spec.rb +++ b/spec/models/topic_user_spec.rb @@ -208,7 +208,6 @@ describe TopicUser do context 'private messages' do it 'should ensure recepients and senders are watching' do - ActiveRecord::Base.observers.enable :all target_user = Fabricate(:user) post = create_post(archetype: Archetype.private_message, target_usernames: target_user.username); diff --git a/spec/models/user_action_spec.rb b/spec/models/user_action_spec.rb index 6f0c37df7be..5aeaa257816 100644 --- a/spec/models/user_action_spec.rb +++ b/spec/models/user_action_spec.rb @@ -3,7 +3,6 @@ require 'rails_helper' describe UserAction do before do - ActiveRecord::Base.observers.enable :all UserActionCreator.enable end @@ -51,6 +50,8 @@ describe UserAction do end it 'includes the events correctly' do + PostActionNotifier.enable + mystats = stats_for_user(user) expecting = [UserAction::NEW_TOPIC, UserAction::NEW_PRIVATE_MESSAGE, UserAction::GOT_PRIVATE_MESSAGE, UserAction::BOOKMARK].sort expect(mystats).to eq(expecting) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 2ecb556648a..c57a4217040 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -104,9 +104,7 @@ Spork.prefork do # # $redis = DiscourseMockRedis.new # - # disable all observers, enable as needed during specs - # - ActiveRecord::Base.observers.disable :all + PostActionNotifier.disable SearchIndexer.disable UserActionCreator.disable NotificationEmailer.disable diff --git a/spec/models/post_alert_observer_spec.rb b/spec/services/post_action_notifier_spec.rb similarity index 97% rename from spec/models/post_alert_observer_spec.rb rename to spec/services/post_action_notifier_spec.rb index be6f8c7876c..b04b7c032f4 100644 --- a/spec/models/post_alert_observer_spec.rb +++ b/spec/services/post_action_notifier_spec.rb @@ -1,10 +1,10 @@ require 'rails_helper' require_dependency 'post_destroyer' -describe PostAlertObserver do +describe PostActionNotifier do before do - ActiveRecord::Base.observers.enable :post_alert_observer + PostActionNotifier.enable end let!(:evil_trout) { Fabricate(:evil_trout) } diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb index 48689faae4f..ff160244f33 100644 --- a/spec/services/post_alerter_spec.rb +++ b/spec/services/post_alerter_spec.rb @@ -63,8 +63,7 @@ describe PostAlerter do context 'edits' do it 'notifies correctly on edits' do - - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles') @@ -89,7 +88,7 @@ describe PostAlerter do context 'likes' do it 'notifies on likes after an undo' do - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles') @@ -101,7 +100,7 @@ describe PostAlerter do end it 'notifies on does not notify when never is selected' do - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles') @@ -110,12 +109,11 @@ describe PostAlerter do PostAction.act(evil_trout, post, PostActionType.types[:like]) - expect(Notification.where(post_number: 1, topic_id: post.topic_id).count).to eq(0) end it 'notifies on likes correctly' do - ActiveRecord::Base.observers.enable :all + PostActionNotifier.enable post = Fabricate(:post, raw: 'I love waffles')