0

I'm trying to set a default scope so that Users where notified: true are soft-deleted. notified is a boolean data column.

This is what I've tried:

class User < ActiveRecord::Base
  default_scope { where('notified != ?', true) }
  #...
end

But this way, no users appear in any scope. ie - all the users appear to be soft-deleted, even the ones with notified: false or notified: nil. What's wrong with my scope?

Taryn East
  • 27,486
  • 9
  • 86
  • 108
Joe Morano
  • 1,715
  • 10
  • 50
  • 114
  • Can you show us the code hat is doing the deleting too? – Taryn East Mar 02 '15 at 00:05
  • @TarynEast Well the users aren't actually being deleted. Setting a default_scope "soft deletes" them, so they are no longer included in database queries, but they're still in the database. I don't believe there is any other relevant code. – Joe Morano Mar 02 '15 at 00:36
  • Yes.. the line of code that actually deletes the users. Are you using `User.delete_all` or what? – Taryn East Mar 02 '15 at 00:39
  • Sorry you said int he question they are all being deleted, and in your comment you say none of them are deleted... which is which? – Taryn East Mar 02 '15 at 00:39
  • oh wait - you don't mean they're deleted.. you mean "the users aren't showing up when i try to get users"... that's a very different thing. – Taryn East Mar 02 '15 at 00:40
  • @TarynEast It's called "soft-deletion" when the records are technically still in the database but they won't be returned by any queries. – Joe Morano Mar 02 '15 at 01:03
  • Thanks Joe, I'm aware of what soft-deletion is - the wording for me was not clear as to what you were trying to do. how about I edit your question to something that would have made it clear for me. – Taryn East Mar 02 '15 at 01:52

2 Answers2

2

I recommend using boolean values the database understands. In this case you want to see users that have a notified that is not true, so I'd user:

default_scope { where('notified IS NOT TRUE') }

That way users will only appear in other scopes if their boolean database values is FALSE or NULL.

Note: default scopes are actually considered a code smell... because they're a bit magic and hide away what you really mean when you fetch out users. You might want to instead create an active and inactive scope and specify them explicitly in your code eg:

scope :active ->{ where('notified IS NOT TRUE') }
scope :inactive ->{ where('notified IS TRUE') }

# in your controller
def index
  @users = User.active.all
end
Taryn East
  • 27,486
  • 9
  • 86
  • 108
1

According to your objective of 'set a default scope so that Users where notified != true are soft-deleted.', you should use default_scope { where(manual_down: true) }, which will only retrieve the records with that column is TRUE, and ignore the others (FALSE or NIL)

I totally agree with Taryn East. Changing/removing default_scope might require lots of modification to logic that depends on that model, so use it only if you're sure you don't change the default_scope condition later (which is usually not the case).

Duc Phan
  • 11
  • 3
  • Oh, that was a mistake on my part. I meant to say that I want to soft-delete the Users where `notified: true`. How can I ignore records where the column is TRUE? – Joe Morano Mar 02 '15 at 01:09
  • Hmm, your scope should work as you're describing. You sure it's a boolean data type and not a String data type? Can you paste the result of `User.unscoped.where("notified is not null").map(&:notified).uniq` – Duc Phan Mar 02 '15 at 01:15
  • Yes, it's definitely a boolean. `User.unscoped.where("notified is not null")` just prints out a list of all the relevant records. – Joe Morano Mar 02 '15 at 01:20
  • Actually I just figured out that `User.where('notified != ?', true)` includes Users where notifed=false, but not where notified is nil. – Joe Morano Mar 02 '15 at 01:30
  • If so, I recommend @Taryn East solution, `default_scope { where("notified IS NOT TRUE") }` seems to work with your case – Duc Phan Mar 02 '15 at 01:47