48

Assume I have this model:

class Conversation < ActiveRecord::Base
  enum status: [ :active, :archived ]
end

How can I find all active conversations without using the numeric value of the enum or without having to iterate over each conversation?

I tried doing Conversation.where(status: :active), but it didn't yield any results.

The only solution comes to mind is to iterate over all conversations and select the active ones, but it doesn't look like a good solution.

Conversation.all.select {|conversation| conversation.active? }  

Is there anything I can do about this?

Abdulaziz
  • 2,201
  • 1
  • 21
  • 35

6 Answers6

62

ActiveRecord::Enum provides scopes based on its values.

Just try:

Conversation.active

or

Conversation.archived

Of course, you can create your own scopes as Kyle Decot mentioned.

Community
  • 1
  • 1
Kensuke Naito
  • 776
  • 6
  • 4
  • 2
    Not really a solution if you are passing that type value as a string say via an API request or query string value. – Chris Nicola Aug 02 '16 at 21:11
48

This works great:

Conversation.where("conversation.status = ?", Conversation.statuses[:active])

For some reason this does NOT work:

Conversation.where(status: :active) #searches for NULL
Conversation.where(status: 'active') #searches for status=0 no matter what the enum

Update

All the above statements work with Rails 5. Happy coding!

Mirror318
  • 11,875
  • 14
  • 64
  • 106
  • 19
    Note that Rails 5 will allow all these statements to work. Woo! – Mirror318 May 19 '16 at 03:16
  • 3
    The answer can be rewritten as `Conversation.where(status: Conversation.statuses[:active])`. No need for strings. – rubyprince Apr 04 '17 at 11:33
  • 1
    Just switched back to work on a Rails 4 project and thought I was going nuts. Thank you for noting that these are Rails 5 conventions. – Greg Blass May 09 '17 at 19:38
  • 2
    Unfortunately Rails 5 doesn't fix querying through a parent (e.g. `Person.joins(:conversations).where(conversations: {status: :active})` errors out). Have to use the first method for that yet (`Person.joins(:conversations).where(conversations: {status: Conversation.statuses[:active]})`). – Abe Voelker Nov 17 '17 at 20:47
28

ActiveRecord::Enum provides built-in scopes based on the values so you can simply do:

Conversation.active
Conversation.archived
Kyle Decot
  • 20,715
  • 39
  • 142
  • 263
8
Conversation.where(status: Conversation.statuses[:active])
6ft Dan
  • 2,365
  • 1
  • 33
  • 46
  • 3
    No need to create a new instance - `Conversation.statuses[:active]` should work – joshua.paling Nov 19 '14 at 00:27
  • 1
    Nice!, this way I can do "or" expressions: Conversation.where(status: [Conversation.statuses[:active], Conversation.statuses[:archived]]) – MegaTux Apr 20 '16 at 18:26
  • 1
    Also, if you wanted the opposite (ie. all records where status is anything other than active): Conversation.where.not(status: Conversation.statuses[:active]) – rmcsharry Nov 16 '17 at 20:32
4

Did you try Conversation.where(status: [:active, :archived]) ? As listed here.

Shifa Khan
  • 769
  • 6
  • 12
  • This one never worked for me. Everytime i have to match every record with the same state as my object I have to do `Conversation.where(status: Conversation.statuses[my_conversation.status])`. Any idea why it doesn't work ? – Logar Feb 26 '16 at 11:23
  • 1
    @Logar Maybe isn't supposed to.. Check https://github.com/rails/rails/issues/19964 – Shifa Khan Feb 26 '16 at 12:25
  • Hehe, I got lured by documentation. At least now I know ! – Logar Feb 26 '16 at 12:49
  • Conversation.where(status: [Conversation.statuses[:active], Conversation.statuses[:archived]]) – MegaTux Apr 20 '16 at 18:25
-8

try this:

.enum :status => {:active => "active", :archived => "archived"ok_off => "took off"}
AbcAeffchen
  • 14,400
  • 15
  • 47
  • 66
jasmo2
  • 525
  • 7
  • 13