How to filter IS NULL in ActiveAdmin?
Asked Answered
E

5

22

I've a table with an integer column called "map_id", I want to add an activeadmin filter to filter if this column IS NULL or IS NOT NULL.

How could this be implemented ?

I tried the following filter

filter :map_id, :label => 'Assigned', :as => :select, :collection => {:true => nil, :false => ''}

But, I get the following error message :

undefined method `map_eq' for #

Exegesis answered 20/8, 2012 at 12:57 Comment(1)
I made some edits, if you have the permissions, please take a quick look and approve them. I think this is a rather common questions and it's wort having it out there with working info. Thanks for asking.Xenocryst
B
15

Not found a good solution but here is a how. filters of Active_admin are accomplished by meta_search, you can override the functions automatically generated by meta_search in your model to get the behavior that you want, the best way is to use the scope since you need to return a relation in order to chain with other query/scopes, as stated here

in your model:

for :as=>:select filters, acitve_admin use the _eq wheres, here is the source code

scope :map_eq, 
        lambda{ |id|
        if(id !='none')
            where( :map_id=> id)
        else
            where( :map_id=> nil)
        end
        }

#re-define the search method:
search_method :map_eq, :type => :integer

in your ative_admin register block:

filter :map_id, :label => 'Assigned', :as => :select, :collection => [['none', 'none'], ['one', 1],['tow', 2]]

# not using :none=>nil because active_admin will igore your nil value so your self-defined scope will never get chained.

Hope this help.

Broadspectrum answered 27/8, 2012 at 6:15 Comment(3)
I made some edits, if you have the permissions, please take a quick look and approve them. I think this is a rather common questions and it's wort having it out there with working info. Thanks for the initial lead, you made pretty much the whole solution! Thanks!Xenocryst
Another example: Nested in ActiveAdmin.register MyModel, you add filter :available, :as => :select, :label => "Availability", :collection => { :Available => true, :Assigned => false }. Then, to implement the scope in MyModel: search_method :available_eq; scope :available_eq, ->(_){ where("user_id is #{:not unless ActiveRecord::ConnectionAdapters::Column.value_to_boolean(_)} null") }Technical
Thank you, @gret -- Would not have figured out how to make my example work without your answerTechnical
H
38

If anyone is happening on this thread belatedly, there is now an easy way to filter for null or non null in active admin :

filter :attribute_present, :as => :boolean 
filter :attribute_blank,   :as => :boolean  

It is no longer necessary to add a custom method to the scope to accomplish this.

Humiliate answered 5/1, 2015 at 11:38 Comment(4)
Note that this can cause SQL errors depending on the data type: it works best with string values and will break when used with datetimes.Brainpan
And for anyone trying to apply the filter through the query string of a link, you would do admin_resources_path('q[attribute_blank]' => true)Lanyard
For integer fields use _null or _not_null instead: filter :attribute_not_null, as: :boolean filter :attribute_null, as: :booleanDefame
@Samuel-innovega answer works for datetimes/timestamps as well - for date/datetime fields use _null or _not_null filter :datetime_attr_null, as: :booleanJig
B
15

Not found a good solution but here is a how. filters of Active_admin are accomplished by meta_search, you can override the functions automatically generated by meta_search in your model to get the behavior that you want, the best way is to use the scope since you need to return a relation in order to chain with other query/scopes, as stated here

in your model:

for :as=>:select filters, acitve_admin use the _eq wheres, here is the source code

scope :map_eq, 
        lambda{ |id|
        if(id !='none')
            where( :map_id=> id)
        else
            where( :map_id=> nil)
        end
        }

#re-define the search method:
search_method :map_eq, :type => :integer

in your ative_admin register block:

filter :map_id, :label => 'Assigned', :as => :select, :collection => [['none', 'none'], ['one', 1],['tow', 2]]

# not using :none=>nil because active_admin will igore your nil value so your self-defined scope will never get chained.

Hope this help.

Broadspectrum answered 27/8, 2012 at 6:15 Comment(3)
I made some edits, if you have the permissions, please take a quick look and approve them. I think this is a rather common questions and it's wort having it out there with working info. Thanks for the initial lead, you made pretty much the whole solution! Thanks!Xenocryst
Another example: Nested in ActiveAdmin.register MyModel, you add filter :available, :as => :select, :label => "Availability", :collection => { :Available => true, :Assigned => false }. Then, to implement the scope in MyModel: search_method :available_eq; scope :available_eq, ->(_){ where("user_id is #{:not unless ActiveRecord::ConnectionAdapters::Column.value_to_boolean(_)} null") }Technical
Thank you, @gret -- Would not have figured out how to make my example work without your answerTechnical
T
5

seems search_method doesn't work in recent rails version, here is another solution:

add scope to your model:

  scope :field_blank, -> { where "field is null" }
  scope :field_not_blank, -> { where "field is not null" } 

add to /app/admin/[YOUR MODEL]

   scope :field_blank
   scope :field_not_blank

you will see buttons for these scopes appear (in top section, under model name, not in filter section)

Trousseau answered 23/1, 2014 at 3:50 Comment(1)
Thanks, this saved my life. Note that ActiveAdmin's default setup doesn't provide a way to clear a scope, so if you want to reset the scope you should manually define an "Everything" scope and add that.Brainpan
O
2

The new version of ActiveAdmin uses Ransacker. I manage to got it working this way:

On the admin

filter :non_nil_map_id, :label => 'Assigned', :as => :select, :collection => [['none', 'none'], ['one', 1],['tow', 2]]

For consistency, I took the same code from @Gret answer just changing the filter name

On your model

ransacker :not_nil_map_id, :formatter => proc {|id|  map_id != 'none' ? id : 'none' } do |parent|
    parent.table[:id]
end

This should trigger a search against nil in case the id is 'none', and active record will return all the nil id entries.

This thread helped a lot.

Oppen answered 10/3, 2014 at 17:44 Comment(0)
I
0

With ransackable scopes:

On the ActiveAdmin resource definition:

filter :map_id, :label => 'Assigned', as: :select, :collection => [['Is Null', 'none'], ['Not null', 'present']]

On your model:

scope :by_map_id, ->(id) { (id == 'none' ? where(map_id: nil) : where('map_id IS NOT NULL')) }

def self.ransackable_scopes(_auth_object = nil)
  %i[by_map_id]
end
Isleen answered 2/8, 2018 at 12:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.