rubysherpas / paranoia

acts_as_paranoid for Rails 5, 6 and 7
Other
2.87k stars 524 forks source link

validations run on .destroy #360

Open JeremiahChurch opened 7 years ago

JeremiahChurch commented 7 years ago

We stumbled across a case in our production environment that we haven't seen before. When calling a destroy operation we're seeing a validation failure that prevents the destroy operation from completing.

In reading the rails docs and poking around it's my understanding that the destroy operation doesn't normally run any validations. I was expecting the destroy operation to succeed and the deleted_at column to be set but not validations to be run.

any help would be greatly appreciated!

paranoia 2.1.5 rails 4.2.7.1 on ruby 2.2.5

class TestPrice < ActiveRecord::Base
  acts_as_paranoid
  has_many :tests
  ....
end

class Test < ActiveRecord::Base
  acts_as_paranoid
  belongs_to :test_price
  validates_presence_of :test_price, message: "I thought validations aren't called on destroy?"
  ...
end

> t = Test.first
> t.valid?
true
> t.update_column('test_price_id', nil)
true
> t.valid?
false
> t.destroy
ActiveRecord::RecordInvalid: Validation failed: Test price I thought validations aren't called on destroy?
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/validations.rb:79:in `raise_record_invalid'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/validations.rb:43:in `save!'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:291:in `block in save!'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:220:in `transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:291:in `save!'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/persistence.rb:265:in `block in update!'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:351:in `block in with_transaction_returning_status'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:220:in `transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:348:in `with_transaction_returning_status'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/persistence.rb:263:in `update!'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/enum.rb:126:in `block (4 levels) in enum'
... 42 levels...
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `block in transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/transaction.rb:184:in `within_new_transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/connection_adapters/abstract/database_statements.rb:213:in `transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:220:in `transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/activerecord-4.2.7.1/lib/active_record/transactions.rb:277:in `transaction'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/paranoia-2.1.5/lib/paranoia.rb:76:in `destroy'
    from (irb):2
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/railties-4.2.7.1/lib/rails/commands/console.rb:110:in `start'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/railties-4.2.7.1/lib/rails/commands/console.rb:9:in `start'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/railties-4.2.7.1/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/railties-4.2.7.1/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /home/tongboy/.rvm/gems/ruby-2.2.5/gems/railties-4.2.7.1/lib/rails/commands.rb:17:in `<top (required)>'
BenMorganIO commented 7 years ago

Do you know if this is still in an issue in 2.2?

Do you have any rails callbacks doing anything? They could be calling an update or something onto an already deleted record.

JeremiahChurch commented 7 years ago

Yes - still an issue with 2.2 - reproduced with the head of 2.2 - commit 'f960e52'.

same behavior with all callbacks disabled on both models (no related callbacks anyways.)

I'd be happy to put together a minimal test case app if that would be helpful?