In short, I’m killing is_paranoid. It’ll still exist as a github repo (mostly as an example of hack-ery and buffoon-ery) and you’re still welcome to use it if you insist. However, I’m no longer going to support it or continue development on it. I’m sorry to anyone this affects.
I created is_paranoid as an example of using “default_scope” to simulate acts_as_paranoid. It was a proof-of-concept and a toy that caught on for whatever reason. I liked it because the original version was ridiculously simple to grok and it was a fun example of the power of default_scope.
But over time, I found out that default scope isn’t as default as I had thought, and is_paranoid became a pile of hacks upon hacks to overcome unexpected behaviors in ActiveRecord and unexpected, complicated use-cases. It became a pain and a mess.
About default_scope not being default-enough for is_paranoid: Imagine you have a product model with a default scope that specifies that only products with in_stock = true should be selected (we don’t want to show out-of-stock products by default). Cool, that works on simple finds. Now let’s imagine we have categories which have many products. Category.find(:first, :include => :products) works, but it doesn’t respect the default_scope on the eager-loading of products so you get out-of-stock items. This applies to all relationships that are eager-loaded, not just has_many. It also isn’t respected on has_many :through relationships (eager-loaded or otherwise). It also probably isn’t respected in a few other places I can’t recall offhand.
Don’t get me wrong, I’m not claiming ActiveRecord or default_scope should be implemented differently or that I could do it better. It just turns out that even though you can implement a rudimentary soft-deletion with default_scope I don’t think you should do it. The problem wasn’t ActiveRecord, the problem was how I was using default_scope. It just doesn’t hold up long-term.
Another issue is that once a scope is applied (default, named, otherwise), it isn’t possible to easily subtract that scope. is_paranoid used with_exclusive_scope to find soft-deleted items, but with_exclusive_scope makes things like Person.female.with_destroyed break since with_exclusive_scope undoes the female scope. There’s no obvious easy way to just pop out the is_paranoid scope and leave the other scopes.
And you can overcome these things (and you can surely do it more cleanly than I did), but it will always be a hack because in the end you’re trying to make ActiveRecord behave differently than it wants to in several different places.
More than just is_paranoid becoming hacky, I’m also subscribing to Rick Olson’s reason for not using acts_as_paranoid anymore (even though he’s the author). This is a sentiment echoed by Ben Johnson in his post about discontinuing Resourcelogic. Simply put, you lose intent by relying on magic. It makes a lot more sense to just be explicit about things using named_scopes or something similar.
I’m biting the hand that feeds me to an extent here since is_paranoid has been my most popular open source project. But I’d rather not be known than be known for something I don’t believe in.
Remember that just because you can do something doesn’t mean you should.
I wouldn’t recommend using is_paranoid unless you want to fight with it. And make sure you write a lot of tests :/
I do want to thank the people who reported bugs and contributed solutions to is_paranoid. I genuinely appreciate it.
Well, now that I’ve sufficiently bummed myself out, I’m going to go back to hacking (the good kind, heh) on a fun little project that should be announced here in a day or two. Ob-la-di, ob-la-da, right?