views:

91

answers:

3

In my model "Post.rb", I'm trying to have it only return posts if column deleted is 0. In other words, when the user deletes posts, it doesn't remove the item from the database, but rather turns deleted to 1. So if I run Post.find(:all), I want it to automatically add the condition "deleted = '0'". How do I go about doing this from my model?

Thanks!

+2  A: 

The simplest way is probably to add a default scope to your Post.rb model:

default_scope :conditions => {:deleted => 0}
Alex Reisner
+1  A: 

In your model, you'll want to specify a default_scope. When you want to actually fetch these deleted posts, you'll have to override the default scope.

class Post < ActiveRecord:Base default_scope :conditions => {:deleted => 0'} end

Jeff Paquette
+2  A: 

Yes, default_scope is going to be simplest method and will allow you to continue using things like Post.find(:all) without worrying about deleted entries, but you might want to ask yourself why you're keeping deleted records around anyway. Would you lose anything of value by simply deleting them? If so, there might be a better answer than a "soft-delete". The trouble with soft deletes, for example, argues very heavily against the practice, and provides a few suggestions for avoiding them.

I personally have nothing against default_scope, but it can get messy, and in the few times that I have used it, I've always had to either go back and remove it, or put in ugly with_exclusive_scope helper methods in my model to explicitly get around it.

So, while not as easy as Post.find(:all), I would recommend using a named_scope instead

class Post < ActiveRecord::Base
  named_scope :active, :conditions => {:deleted => 0}
end

and then using Post.active.find(:all) or Post.active.find(params[:id]). I think it conveys the intention of the code more clearly, it then lets you redefine what "active" is in the future if your business logic changes, and it doesn't make you jump through with_exclusive_scope hoops if you really do want to retrieve Post.find(:all) (in an admin app, for instance).

Edit: As I suspected, it looks like you're already looking for ways to get around it. :)

Edit 2: You might want to look at the acts_as_paranoid gem, which looks to manage a lot of this stuff for you (while still giving you access to deleted records without using with_exclusive_scope).

jerhinesmith
Good point about soft deletes, but I think there's still some value in using default_scope with with_exclusive_scope since it gives you some protection against making errors later in your business logic: For example, if I have "secret" posts, then creating a named scope for "active" means you need to explicitly specify the "default case"while if i have a default scope, the secret posts will excluded even with Post.find(:all) unless i explicitly specify i want them to be shown. IMO in these cases default_scope is a safer choice.
bdon
Good point. I think it comes down to what you're really trying to do. I'm merely trying to stress that, as developers, I think we too often go down the "soft delete everything!" rabbit hole without really stopping to consider 1) What are we really trying to save?, and 2) Is there a better way to do this? So, while :is_secret_photo seems to me like valid business logic, :is_deleted seems more like a knee-jerk reaction to a problem that may or may not exist.Or, it could just be that I'm alone in my war against the soft-delete. :)
jerhinesmith