如何在选项卡内的 Active Admin 显示页面上添加 sortable table?

How to add a sortable table on ActiveAdmin's show page inside a tab?

考虑以下场景:我在 ActiveAdmin 中有一个包含 indexshow 页面的资源,而在显示页面上我有更多 Tabs

在其中一些(可能不止一个)Tabs中,我想以表格形式显示与资源相关的信息,并带有可排序的列。 我还要求应用程序在更改表的排序顺序时保留在选定的 Tab 上。

如何在 ActiveAdmin 中实现这一点?

不幸的是,ActiveAdmin 似乎不支持这个开箱即用的功能,但它是可以实现的。

ActiveAdmin.register 调用中(通常在 lib/admin/resource.rb 中)这将为 resourcesome_connection 数据创建一个 table:

tab "Tab 2" do
  table_for resource.some_connection do
    column :name
    ...
  end
end

不幸的是,这不是排序table table,因此我们应该简单地添加以下选项哈希:

{:sortable => true, :class => 'index_table'}

像这样:

table_for resource.some_connection, {:sortable => true, :class => 'index_table'} do

好吧,这差不多行得通了。遗憾的是,选择排序列会将您带回到第一个 Tab,但排序将存储在 URL 中(以 whatever/your/page/address/is?order=name_asc 格式)。

为了解决这个问题,我使用以下内容对 ActiveAdmin's TableFor class 进行了猴子修补(在我在项目结构中创建的新文件中,例如:ext/active_admin/views/table_for ):

module ActiveAdmin
  module Views
    class TableFor

      def build(obj, *attrs)
        options         = attrs.extract_options!
        @sortable       = options.delete(:sortable)
        @collection     = obj.respond_to?(:each) && !obj.is_a?(Hash) ? obj : [obj]
        @resource_class = options.delete(:i18n)
        @resource_class ||= @collection.klass if @collection.respond_to? :klass
        @columns        = []
        @row_class      = options.delete(:row_class) 
        @anchor         = options.delete(:anchor)
        @sort_key_prefix = ''
        @sort_key_prefix = @anchor.to_s + '_' unless @anchor.nil?

        build_table
        super(options)
        columns(*attrs)
      end

      def build_table_header(col)
        classes  = Arbre::HTML::ClassList.new

        sort_key = sortable? && col.sortable? && col.sort_key

        params   = request.query_parameters.except :page, :order, :commit, :format

        classes << 'sortable'                         if sort_key
        classes << "sorted-#{current_sort[1]}"        if sort_key && current_sort[0] == @sort_key_prefix + sort_key
        classes << col.html_class

        if sort_key
          th class: classes do
            link_to col.pretty_title, params: params, order: "#{@sort_key_prefix}#{sort_key}_#{order_for_sort_key(@sort_key_prefix + sort_key)}", anchor: @anchor
          end
        else
          th col.pretty_title, class: classes
        end
      end

    end
  end
end 

基本上我在选项中添加了一个锚参数,使用它我们可以在选择排序条件后返回到 table 所在的选项卡。这些条件的名称以这个锚点作为前缀进行扩展,因此在不同的选项卡中使用相同名称的列不会弄乱不同 table 的排序。 (目前我使用锚作为前缀,但这可以更改为一个完全独立的选项参数,以在一个 Tab 中支持更多 table)

我使用初始化程序加载猴子补丁,它只需要包含上面代码的文件(在我的示例中为 ext/active_admin/views/table_for):

monkey_patches.rb
-----------------
require 'ext/active_admin/views/table_for'

这些更改要求我们稍微修改构建 table 的方式(我们必须从 params 中检索排序设置并将其应用于我们的数据):

tab_name = "Tab 2"
tab tab_name do
  tab_anchor = tab_name.parameterize('_')

  data = resource.some_conection
  unless params['order'].nil?
    order = params['order'].to_s.sub(tab_anchor + '_', '').sub("_asc", " ASC").sub("_desc", " DESC")
    data = data.order(order) unless order.nil?
  end

  table_for data, { anchor: tab_anchor, :sortable => true, :class => 'index_table'} do
    column :name
    ...
  end
end

这是结果(这里table实际上被放入了一个Panel,而anchor指向那个):

实际上,ActiveAdmin 支持这个。

要对 table 进行排序,请调用 order() 方法并传递列名和 desc/asc,如:

table_for boat.bookings.order('created_at desc') do
  column :name
  column :created_at
end

感谢 Ryan Bates 的截屏视频:http://railscasts.com/episodes/284-active-admin?view=asciicast