Best way to delete a user

Hi guys,

What is the safest and most comprehensive way to delete a user from the system?

Not sure what “DELETE” would mean in terms of database but I am looking for the industry standard (what Facebook, LinkedIn, etc. would do when they delete their users)

I assume all user info, transaction history, messages, etc. will be gone.

I also assume that it will be the same as when the user clicks the button “DELETE ACCOUNT” under their settings.

Thanks!

Hi Duc,

Do you want an user can be DELETE by the administrator (and from the admin panel) or that the user can be DELETE his own account himself ?

Cheers :slightly_smiling_face:

Hi @phatza sorry for not clarifying.
I want the admin to be able to do it.
This is because we have many ghost users on the platform and we need to remove them manually.

Hi @freelensia

Unfortunatly, there is no similar DELETE user’s option from admin panel.
You have to create it yourself from the source code.

Can anyone confirm this ?

Regards

Hi @phatza

Appreciate the response !

Yes, there is no direct “button” to do that in the admin panel.

What I am wondering the ST team could help explain is how to do it in SQL or Rails command, that would be the cleanest and most professional way to do it.

@thomasmalbaux any ideas?

You can check the code that is executed when user deletes own account:

https://github.com/sharetribe/sharetribe/blob/master/app/models/person/concerns/delete_person.rb
https://github.com/sharetribe/sharetribe/blob/master/app/controllers/people_controller.rb#L283

Note that it does not remove existing messages and transactions, instead they render as being from “[deleted user]” , so other participants are not suprised that items from their Inbox disappear for unknown reason.

1 Like

Great answer, thanks Zenik :candy:

Hi guys,

I am trying to delete all users except for some, to create a staging database that does not contain real users.

I tried this command:

array = ["q0...g","rZ...A"] 
Person::Concern:: Person.all.each do |people|
DeletePerson.delete_user(people.id) unless array.include?(people.id)
end

The error I got was:
NameError: uninitialized constant DeletePerson
from (irb):11:in `block in irb_binding’
from (irb):10

I also tried:
Person.all.each …
and
Person.each do |people| …

But there were errors as well.

Could somebody validate my syntax?

Also, is the command the same as the Delete_Person.rb operation that @zenik mentioned?

Syntax of your code is not valid, you can use following:

# by ID
target_user = Person.find("rZ...A")
# or target_user = Person.find_by_username("badusername")
ActiveRecord::Base.transaction do
 Person.delete_user(target_user.id)
 Listing.delete_by_author(target_user.id)
end

# another variant to delete from array of ids
bad_ids = ["q0...g","rZ...A"] 
Person.where(id: bad_ids).each do |user_to_delete|
  ActiveRecord::Base.transaction do
    Person.delete_user(user_to_delete.id)
    Listing.delete_by_author(user_to_delete.id)
  end
end

Thanks @zenik, your code is the same as the Delete_Person.rb operations?

Yes, as this method Person.delete_user is actually defined in app/models/person/concerns/delete_person.rb :slight_smile:

1 Like

Hi @zenik,

But it only deletes the user from Person and Listing tables, right?

Wouldn’t a service like this be more complete?

class DeletePersonService
  attr_reader :usernames

  def initialize usernames
    @usernames = usernames
  end

  def perform
    ids = Person.where(username: usernames).pluck :id
    ids.each do |id|
      delete_user id
    end
  end

  def delete_user id
    person = Person.find_by(id: id)

    if person.nil?
      return false
    else
      # Delete personal information
      person.update_attributes(
        given_name: nil,
        family_name: nil,
        display_name: nil,
        phone_number: nil,
        description: nil,
        email: nil,
        facebook_id: nil,
        username: "deleted_#{SecureRandom.hex(5)}",
        current_sign_in_ip: nil,
        last_sign_in_ip: nil,
        # To ensure user can not log in anymore we have to:
        #
        # 1. Delete the password (Devise rejects login attempts if the password is empty)
        # 2. Remove the emails (So that use can not reset the password)
        encrypted_password: "",
        deleted: true # Flag deleted
      )

      # Delete emails
      person.emails.destroy_all

      # Delete location
      person.location&.destroy

      # Delete avatar
      person.image.destroy
      person.image.clear
      person.image = nil
      person.save(validate: false)

      # Delete follower relations, both way
      person.follower_relationships.destroy_all
      person.inverse_follower_relationships.destroy_all

      # Delete memberships
      person.community_membership.update_attributes(status: "deleted_user")

      # Delte auth tokens
      person.auth_tokens.destroy_all
    end
  end
end

Hi guys,

Just to share with the community. The final code our site uses to delete a user is below. We mimick the behavior of a user deleting his own account.

desc "Delete all accounts except ones that in tmp/keep.yml"

task :delete_all_accounts => :environment do |t, args|
keep_usernames = YAML::load_file(Rails.root.join(‘tmp’, ‘keep_usernames.yml’))

target_users = Person.where.not(username: keep_usernames, deleted: true)

target_users.find_each do |target_user|

  has_unfinished = TransactionService::Transaction.has_unfinished_transactions(target_user.id)
  # Do not delete user who has unfinished transactions.
  next if has_unfinished

  # Start transaction
  ActiveRecord::Base.transaction do
    UserService::API::Users.delete_user(target_user.id)
    MarketplaceService::Listing::Command.delete_listings(target_user.id)

    PaypalService::API::Api.accounts.delete(community_id: target_user.community_id, person_id: target_user.id)
  end
end

end

Steps to execute this rake:

  1. ssh to target server (prod or stag server)
  2. Go to your current folder
  3. Edit the file tmp/keep_usernames.yml using vim or nano.
  4. RAILS_ENV=<enter_your_environment> bundle exec rake yourdbname :delete_all_accounts