Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to query multi values of enum field in ActiveRecord?

mymodel.rb

enum status: { posted: 1, failed: 2, suspended: 3 }

mycontroller.rb

def filter_params
  params.fetch(:mymodel, {}).
  permit(
    :status => []
    )
end

And i have params like mymodel[:status] => ["failed", "suspended"]

How can i get all results by status is failed and suspended

Something like: Mymodel.where(status: filter_params[:status])

Thanks a lot!

And when a call:

@mymodel = Mymodel.new(filter_params)

I got this error:

'["failed", "suspended"]' is not a valid status
like image 592
Hieu Le Avatar asked Feb 02 '15 05:02

Hieu Le


2 Answers

When running a query, you need to supply the ordinal values for the enum attribute. So instead of strings like 'failed' or 'suspended', you need to query using their integer values.

Luckily, you can access a hash to easily map all the statuses to integers from your filter_params hash:

values = Mymodel.statuses.values_at(*Array(filter_params[:status]))

With that you can run your query to get all records which have any of the filtered statuses:

Mymodel.where(status: values)

You don't want to scatter that piece of code all over the place though, so I recommend you'd implement this as a scope in your model:

class Mymodel < ActiveRecord::Base
  enum status: { posted: 1, failed: 2, suspended: 3 }

  scope :for_statuses, ->(values) do
    return all if values.blank?

    where(status: statuses.values_at(*Array(values)))
  end
end

Note that the return all if values.blank? line makes it possible to throw in nil or an empty array without breaking your query.

You can now easily query the records:

Mymodel.for_statuses(filter_params[:status])

Note that you cannot create a record which has multiple statuses. enum only restricts the values that can be assigned, but you can assign only one, otherwise you get the not a valid status error.

See the Rails documentation for more information about enum.

like image 108
fivedigit Avatar answered Oct 06 '22 00:10

fivedigit


In Rails 5 you can now pass a string array to the query, e.g:

Mymodel.where(status: ['failed', 'suspended'])

For earlier versions, just convert your array values to symbols:

statuses = filter_params[:status].map(&:to_sym)
Mymodel.where(status: statuses)
like image 25
eronisko Avatar answered Oct 05 '22 22:10

eronisko