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

Already on GitHub? Sign in to your account

`only_deleted` method does not work on associations #24

Closed
hidde-jan opened this Issue Apr 29, 2012 · 5 comments

Comments

Projects
None yet
3 participants

Hi there,

Currently, the only_deleted method of a model is implemented as

    def only_deleted
      unscoped {
        where("deleted_at is not null")
      }
    end

Because of this, only_deleted can only be called on the class which is marked as acts_as_paranoid. If it is called anywhere else, for instance on an association, then it will behave as if it was called on the class:

irb> Organization.where('LENGTH(name) > 100').only_deleted
Organization Load (1.3ms)  SELECT `organizations`.* FROM `organizations` WHERE (deleted_at is not null)
=> [#<Organization id: ...>, ...]

The behavior I expect is

irb> Organization.where('LENGTH(name) > 100').only_deleted
Organization Load (1.3ms)  SELECT `organizations`.* FROM `organizations` WHERE LENGTH(name) > 100 AND (deleted_at is not null)
=> [#<Organization id: ...>, ...]

So it should somehow only negate the deleted_at IS NULL condition that is set as the default scope.

Furthermore, relations also don't work:

irb> org = Organization.first
=> #<Organization id: 1,...>
irb> org.users.only_deleted
User Load (1.3ms)  SELECT `users`.* FROM `users` WHERE (deleted_at is not null)
=> [...]

You would expect:

irb> org = Organization.first
=> #<Organization id: 1,...>
irb> org.users.only_deleted
User Load (2.7ms)  SELECT `users`.* FROM `users` WHERE organization_id = 1 AND (deleted_at is not null)
=> [...]

Of course, this could be tricky. Since wat would be te behavior of:

Organization.where(:deleted_at => nil).only_deleted

vs.

Organization.only_deleted

I'm willing to write a patch for this if there is support for the behavior.

Thanks,
HJ

Collaborator

radar commented Apr 30, 2012

Yes please submit a patch to fix this. I am not sure why the unscoped is there. I think that's the cause of this problem.

Hi,

unscoped is there, because the default scope is set to

default_scope :conditions => { :deleted_at => nil }

So the query would become SELECT ... WHERE deleted_at is null AND deleted_at is not null. So we need to keep the current scope, but without the default scope.

Hey,

I kinda need more time to fix this. The problem is that a default_scope is set, and that it's possible to set multiple default scopes as far as I know. I haven't found a clean way to disable just the :deleted_at => nil condition.

Contributor

arsduo commented Aug 30, 2012

I've been wrestling with this for two days now, and as far as I can tell there doesn't seem to be a clean way of doing this. While it would be great if Rails solved this (there should be a nice interface for introspecting and altering scopes during the chaining process), I'd settle for allowing us to skip the default scope and have to call .active or .alive or whatever all the time. We're willing to lose the default scope to avoid this problem.

Something like:

class ActiveRecord::Base
  def self.acts_as_slightly_paranoid
    alias_method :destroy!, :destroy
    alias_method :delete!,  :delete
    include Paranoia
  end
end

module Paranoia
  # this could, less colorfully but perhaps more consistently, 
  # also be called without_deleted
  # though active is probably the best compromise, and is shorter
  scope :alive, :conditions => { :deleted_at => nil }
end

If this sounds okay, I can submit a pull request.

@radar radar added a commit that referenced this issue Nov 15, 2012

@radar radar add regression test for #24 131cb29
Collaborator

radar commented Nov 15, 2012

This was fixed with #32. I've added a regression test for this issue now too.

@radar radar closed this Nov 15, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment