如何在ActiveAdmin中筛选IS NULL?

22
我有一个名为“map_id”的整数列的表格,我想添加一个ActiveAdmin筛选器来过滤此列是否为空或非空。

如何实现这个?

我尝试了以下筛选器:

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

但是,我收到了以下错误信息:

未定义方法`map_eq',对象为 #


我进行了一些编辑,如果您有权限,请快速查看并批准它们。我认为这是一个相当常见的问题,并且值得将其与工作信息放在那里。谢谢您的提问。 - David Pelaez
5个回答

38

如果有人迟来到这个线程,现在Active Admin中有一种简单的方法可以过滤null或非null值:

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

现在已经不需要在作用域中添加自定义方法来实现这个了。


5
请注意,这可能会导致SQL错误,具体取决于数据类型:它最适用于字符串值,并且在与日期时间一起使用时会出现故障。 - Topher Hunt
2
对于任何试图通过链接的查询字符串应用过滤器的人,您可以使用admin_resources_path('q[attribute_blank]' => true)。 - LikeMaBell
20
对于整数字段,请使用*_null_not_null*代替:filter :attribute_not_null, as: :booleanfilter :attribute_null, as: :boolean - Samuel Vega
7
@Samuel-innovega的回答同样适用于日期/时间戳 - 对于日期/时间字段,请使用 _null 或 _not_null。 filter :datetime_attr_null, as: :boolean 的意思是“过滤 datetime_attr_null 字段,将其显示为布尔值形式”。 - derrek

15

虽然没有找到完美解决方案,但以下方法或许能帮到您。Active_admin的过滤器是通过meta_search实现的,您可以在模型中重写meta_search自动生成的函数以获得想要的行为方式。最好的方法是使用scope,因为您需要返回一个关联才能与其他查询/范围链式调用,如此所述here

在您的模型中:

对于 :as=>:select 的过滤器,active_admin使用_eq wheres,这里是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

在你的ActiveAdmin注册块中:

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.
希望这可以帮到您。

我进行了一些编辑,如果您有权限,请快速查看并批准它们。我认为这是一个相当常见的问题,并且值得将其与工作信息放在那里。感谢您的初始引导,您几乎完成了整个解决方案!谢谢! - David Pelaez
另一个例子:嵌套在“ActiveAdmin.register MyModel”中,您可以添加filter :available, :as => :select, :label => "Availability", :collection => { :Available => true, :Assigned => false }。然后,在MyModel中实现范围:search_method :available_eq; scope :available_eq, ->(_){ where("user_id is #{:not unless ActiveRecord::ConnectionAdapters::Column.value_to_boolean(_)} null") } - Isaac Betesh
谢谢,@gret -- 没有你的答案,我不会想出如何让我的示例工作。 - Isaac Betesh

5

似乎在最新的Rails版本中,search_method不起作用,这里提供另一个解决方案:

向你的模型添加范围(scope):

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

添加到 /app/admin/[您的模型]

   scope :field_blank
   scope :field_not_blank

你会看到这些范围的按钮出现(在顶部部分,在型号名称下方,而不是在过滤器部分)


谢谢,这救了我的命。请注意,ActiveAdmin的默认设置没有提供清除范围的方法,因此如果您想重置范围,应手动定义一个“Everything”范围并添加它。 - Topher Hunt

2

ActiveAdmin的新版本使用Ransacker。我成功地按照以下步骤使其正常工作:

在管理界面上

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

为了保持一致性,我采用了@Gret的代码,只更改了过滤器名称。

关于你的模型

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

这应该会触发对 nil 的搜索,以防id为“none”,并且Active Record将返回所有的 nil id 条目。
这个线程非常有帮助。

-1

使用可搜索的作用域:

在ActiveAdmin资源定义中:

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

在你的模型上:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接