Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failing to recover parent but has_one association gets recovered #130

Open
frostblooded opened this issue Sep 24, 2019 · 6 comments
Open
Assignees

Comments

@frostblooded
Copy link

frostblooded commented Sep 24, 2019

class User < ApplicationRecord
  ...
  acts_as_paranoid

  has_one :data, dependent: :destroy, class_name: 'Users::Data', as: :holder
  ...
end

module Users
  class Data
    ...
    acts_as_paranoid

    belongs_to :holder, polymorphic: true, touch: true, optional: true, with_deleted: true
    ...
  end
end

I have this interesting case where the user has a unique username, but after he gets soft-deleted the username is freed up. This means that trying to recover a soft-deleted user may fail, because his previous username may now be taken, which means the #recover should fail and return false and it does.

The problem is that I call deleted_user.recover, it fails, and then if I check the deleted_user.data record, it has been recovered even though the parent object has not been recovered. I tried deleted_user.data.reload to see if maybe the deleted_at: nil that I am seeing for the data is only an unsaved value, but no, the data has really been recovered even after a reload or a direct database check.

@mvz mvz self-assigned this Sep 24, 2019
@frostblooded
Copy link
Author

I just realized that right now I am only observing this problem in my test environment. I will look into it and report back if I find anything.

@frostblooded
Copy link
Author

frostblooded commented Sep 25, 2019

Unfortunately, no, it doesn't happen only in my test environment. I have seen the same behaviour in the development environment but not as consistently. When the user should correctly recover, sometimes his data doesn't recover with him for some reason. (all of this happens only sometimes with no change in the code between attempts) I will try to make a reproducible code snippet and upload it here soon.

@shadydealer
Copy link

Taking a shot in the dark here, but I think the problem is the following:
In core.rb:149(the recover method) calls recover for each of its dependent_associations which will wrap the dependent_association in another transaction here:

 self.class.transaction do
        run_callbacks :recover do
          recover_dependent_associations(options[:recovery_window], options) if options[:recursive]

          self.paranoid_value = self.class.paranoid_configuration[:recovery_value]
          self.save
        end
      end

which will update the dependent_assocations value in the database regardless of whether the User recover succeeded or not.

@frostblooded
Copy link
Author

frostblooded commented Sep 27, 2019

I am trying to make a reproducible example in the form https://pastebin.com/TUUMxmu3 (it is probably wrong now, but it can't get past the bundler part), but it throws an error

/home/niki/.rvm/gems/ruby-2.4.6/gems/acts_as_paranoid-0.6.1/lib/acts_as_paranoid/validations.rb:18:in `<class:UniquenessWithoutDeletedValidator>': uninitialized constant ActsAsParanoid::Validations::UniquenessWithoutDeletedValidator::ActiveRecord (NameError)
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/acts_as_paranoid-0.6.1/lib/acts_as_paranoid/validations.rb:9:in `<module:Validations>'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/acts_as_paranoid-0.6.1/lib/acts_as_paranoid/validations.rb:4:in `<module:ActsAsParanoid>'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/acts_as_paranoid-0.6.1/lib/acts_as_paranoid/validations.rb:3:in `<top (required)>'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/acts_as_paranoid-0.6.1/lib/acts_as_paranoid.rb:3:in `require'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/acts_as_paranoid-0.6.1/lib/acts_as_paranoid.rb:3:in `<top (required)>'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/bundler-2.0.2/lib/bundler/runtime.rb:81:in `require'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/bundler-2.0.2/lib/bundler/runtime.rb:81:in `block (2 levels) in require'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/bundler-2.0.2/lib/bundler/runtime.rb:76:in `each'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/bundler-2.0.2/lib/bundler/runtime.rb:76:in `block in require'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/bundler-2.0.2/lib/bundler/runtime.rb:65:in `each'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/bundler-2.0.2/lib/bundler/runtime.rb:65:in `require'
        from /home/niki/.rvm/gems/ruby-2.4.6/gems/bundler-2.0.2/lib/bundler/inline.rb:70:in `gemfile'
        from main.rb:8:in `<main>'

If you can help me with how this script can work, I can look into making my issue reproducible.

@mvz
Copy link
Contributor

mvz commented May 2, 2021

@frostblooded and @shadydealer the order of recovery has changed in version 0.7.3. Can you please check if the problem still occurs with that version?

@frostblooded
Copy link
Author

Unfortunately, I no longer have access to that code, but maybe @shadydealer can check it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants