radar/paranoia — pull request #180 by nbrookie (2014-11-18 22:29:38+00:00)
Title: Possible fix for 'cannot touch a new record object' error when using Shoulda Matchers

This could be super "edgy casey" and not in the scope of Paranoia, but maybe not. So here goes nothing:

If a parent model with a has_one relationship (dependent destroy) to a child model and some custom building logic for that child model, fails validation for some reason, I get some weird behavior when trying to call destroy on the parent, and subsequently the child. Specifically I get a `ActiveRecord::ActiveRecordError: cannot touch on a new record object` error in the parent model in regards to touching `deleted_at` in the child model.

I ran into this when trying to use Shoulda Matchers alongside Paranoia.

Take the following example:
```ruby
#app/models/frowny_person.rb
class FrownyPerson < ActiveRecord::Base
acts_as_paranoid
has_one :face, dependent: :destroy
validates :some_frowny_attr, presence: true
after_validation :build_face, on: :create

private
def build_face
super.tap { |face| face.some_face_attr = "In your face!" }
end
end

#app/models/face.rb
class Face < ActiveRecord::Base
acts_as_paranoid
belongs_to :frowny_person
end

#spec/models/frowny_person_spec.rb
it { should validate_presence_of :some_frowny_attr }
```

From my understanding, what will happen is the Shoulda Matcher library will create a FrownyPerson instance, set the attribute in question to a blank value, and then run validations on it, and test the message it gets back. Where I get a bit fuzzy is, at some point, ActiveRecord will call `destroy` on the `Face` instance that `FrownyPerson` has built. I know it happens because `dependent: :destroy` is set, and I know it happens [here](https://github.com/rails/rails/blob/v4.1.7/activerecord/lib/active_record/associations/has_one_association.rb#L81), and when it does, it triggers all of Paranoia’s destroy logic. Since we are trying to destroy something that is in memory and not in the db yet, we end up trying to touch the `deleted_at` attribute of the `Face` instance, and that causes the error.

I was able to simulate this behavior in the test associated with this pull request, so if it helps, take a look there and let me know what you think.

Again, this case is kinda out there, but it may be relevant.