app/models/user.rb
# Destroying a user triggers a giant, slow, costly cascade of deletions that
# all occur within a transaction. This method tries to circumvent some of
# that madness by assigning communal assets to new users and pre-destroying
# some associates
Destroying a user triggers a giant, slow, costly cascade of deletions that
all occur within a transaction. This method tries to circumvent some of
that madness by assigning communal assets to new users and pre-destroying
some associates
Destroying a user triggers a giant slow costly cascade of deletions that all occur within a transaction . This method tries to circumvent some of that madness by assigning communal assets to new users and pre - destroying some associates
def sane_destroy(options = {})
    start_log_timer "sane_destroy user #{id}"
    taxon_ids = life_list.taxon_ids
    project_ids = self.project_ids
    lists.where("type = 'List'").find_each do |l|
      l.listed_taxa.find_each do |lt|
        lt.skip_sync_with_parent = true
        lt.skip_update_cache_columns = true
        lt.skip_update_user_life_list_taxa_count = true
        lt.destroy
      end
      l.destroy
    end
    User.preload_associations(self, [ :stored_preferences, :roles, :flags ])
    observations.includes([
      { user: :stored_preferences },
      :votes_for,
      :flags,
      :stored_preferences,
      :observation_photos,
      :comments,
      :annotations,
      { identifications: [
        :taxon,
        :user,
        :flags
      ] },
      :project_observations,
      :project_invitations,
      :quality_metrics,
      :observation_field_values,
      :observation_sounds,
      :observation_reviews,
      { listed_taxa: :list },
      :tags,
      :taxon,
      :quality_metrics,
      :sounds
    ]).find_each(batch_size: 100) do |o|
      o.skip_refresh_lists = true
      o.skip_refresh_check_lists = true
      o.skip_identifications = true
      o.bulk_delete = true
      o.comments.each{ |c| c.bulk_delete = true }
      o.annotations.each{ |a| a.bulk_delete = true }
      o.destroy
    end
    identification_observation_ids = Identification.where(user_id: id).
      select(:observation_id).distinct.pluck(:observation_id)
    comment_observation_ids = Comment.where(user_id: id, parent_type: "Observation").
      select(:parent_id).distinct.pluck(:parent_id)
    annotation_observation_ids = Annotation.where(user_id: id, resource_type: "Observation").
      select(:resource_id).distinct.pluck(:resource_id)
    unique_obs_ids = ( identification_observation_ids + comment_observation_ids +
      annotation_observation_ids ).uniq
    identifications.includes([
      :observation,
      :taxon,
      :user,
      :flags
    ]).find_each(batch_size: 100) do |i|
      i.observation.skip_indexing = true
      i.observation.bulk_delete = true
      i.bulk_delete = true
      i.destroy
    end
    identification_observation_ids.in_groups_of(100, false) do |obs_ids|
      Observation.where(id: obs_ids).includes(
        { user: :stored_preferences },
        :votes_for,
        :flags,
        :taxon,
        { photos: :flags },
        { identifications: [ :taxon, { user: :flags } ] },
        :quality_metrics
      ).each do |o|
        Identification.update_categories_for_observation( o, { skip_reload: true, skip_indexing: true } )
        o.update_stats
      end
      Identification.elastic_index!(scope: Identification.where(observation_id: obs_ids))
    end
    comments.find_each(batch_size: 100) do |c|
      c.bulk_delete = true
      c.destroy
    end
    annotations.includes(:votes_for).find_each(batch_size: 100) do |a|
      a.votes_for.each{ |v| v.bulk_delete = true }
      a.bulk_delete = true
      a.destroy
    end
    Project.where(:user_id => id).find_each do |p|
      if p.observations.exists?
        if manager = p.project_users.managers.where("user_id != ?", id).first
          p.user = manager.user
          manager.role_will_change!
          manager.save
        else
          pu = ProjectUser.create(:user => User.admins.first, :project => p)
          p.user = pu.user
        end
        p.save
      else
        p.destroy
      end
    end
    Observation.elastic_index!(ids: unique_obs_ids )
    destroy
    taxon_ids.in_groups_of(100) do |group|
      CheckList.delay(:priority => OPTIONAL_PRIORITY, :queue => "slow").refresh(:taxa => group.compact)
    end
    project_ids.in_groups_of(100) do |group|
      ProjectList.delay(:priority => INTEGRITY_PRIORITY).refresh(:taxa => group.compact)
    end
    end_log_timer
  end
def sane_destroy ( options = { } ) start_log_timer "sane_destroy user #{id}" taxon_ids = life_list . taxon_ids project_ids = self . project_ids lists . where ( "type = 'List'" ) . find_each do | l | l . listed_taxa . find_each do | lt | lt . skip_sync_with_parent = true lt . skip_update_cache_columns = true lt . skip_update_user_life_list_taxa_count = true lt . destroy end l . destroy end User . preload_associations ( self , [ :stored_preferences , :roles , :flags ] ) observations . includes ( [ { user : :stored_preferences } , :votes_for , :flags , :stored_preferences , :observation_photos , :comments , :annotations , { identifications : [ :taxon , :user , :flags ] } , :project_observations , :project_invitations , :quality_metrics , :observation_field_values , :observation_sounds , :observation_reviews , { listed_taxa : :list } , :tags , :taxon , :quality_metrics , :sounds ] ) . find_each ( batch_size : 100 ) do | o | o . skip_refresh_lists = true o . skip_refresh_check_lists = true o . skip_identifications = true o . bulk_delete = true o . comments . each { | c | c . bulk_delete = true } o . annotations . each { | a | a . bulk_delete = true } o . destroy end identification_observation_ids = Identification . where ( user_id : id ) . select ( :observation_id ) . distinct . pluck ( :observation_id ) comment_observation_ids = Comment . where ( user_id : id , parent_type : "Observation" ) . select ( :parent_id ) . distinct . pluck ( :parent_id ) annotation_observation_ids = Annotation . where ( user_id : id , resource_type : "Observation" ) . select ( :resource_id ) . distinct . pluck ( :resource_id ) unique_obs_ids = ( identification_observation_ids + comment_observation_ids + annotation_observation_ids ) . uniq identifications . includes ( [ :observation , :taxon , :user , :flags ] ) . find_each ( batch_size : 100 ) do | i | i . observation . skip_indexing = true i . observation . bulk_delete = true i . bulk_delete = true i . destroy end identification_observation_ids . in_groups_of ( 100 , false ) do | obs_ids | Observation . where ( id : obs_ids ) . includes ( { user : :stored_preferences } , :votes_for , :flags , :taxon , { photos : :flags } , { identifications : [ :taxon , { user : :flags } ] } , :quality_metrics ) . each do | o | Identification . update_categories_for_observation ( o , { skip_reload : true , skip_indexing : true } ) o . update_stats end Identification . elastic_index! ( scope : Identification . where ( observation_id : obs_ids ) ) end comments . find_each ( batch_size : 100 ) do | c | c . bulk_delete = true c . destroy end annotations . includes ( :votes_for ) . find_each ( batch_size : 100 ) do | a | a . votes_for . each { | v | v . bulk_delete = true } a . bulk_delete = true a . destroy end Project . where ( :user_id => id ) . find_each do | p | if p . observations . exists? if manager = p . project_users . managers . where ( "user_id != ?" , id ) . first p . user = manager . user manager . role_will_change! manager . save else pu = ProjectUser . create ( :user => User . admins . first , :project => p ) p . user = pu . user end p . save else p . destroy end end Observation . elastic_index! ( ids : unique_obs_ids ) destroy taxon_ids . in_groups_of ( 100 ) do | group | CheckList . delay ( :priority => OPTIONAL_PRIORITY , :queue => "slow" ) . refresh ( :taxa => group . compact ) end project_ids . in_groups_of ( 100 ) do | group | ProjectList . delay ( :priority => INTEGRITY_PRIORITY ) . refresh ( :taxa => group . compact ) end end_log_timer end
Destroying a user triggers a giant, slow, costly cascade of deletions that
all occur within a transaction.
Destroying a user triggers a giant slow costly cascade of deletions that all occur within a transaction .
# delete lists without triggering most of the callbacks # delete observations without onerous callbacks # transition ownership of projects with observations, delete the rest # delete the user # refresh check lists with relevant taxa # refresh project lists
options