misza222
misza222

Reputation: 393

Group records on activeadmin resource index page

I have 2 resources - Shelf and Book, where each Shelf has many Books.

Is there any way to groups books (on Book index page) by Shelf? Specifically I would like to have Books sorted by Shelf and whenever Shelf changes, I would like to indicate that on the books list (inserting a h3 title with new shelf name between books on one shelf and books on the other)

I am using rails 3.2 and activeadmin 0.6.0.

Upvotes: 5

Views: 3453

Answers (2)

glasz
glasz

Reputation: 2565

using ActiveAdmin 1.0.0.pre2 on Rails 4.2.5.2, it turned out to be quite simple. the solution is essentially only 20 lines of a custom ActiveAdmin view class.

note the file names on the first line as a hint where to put the code or make additions/changes to existing files.

# config/application.rb
module MyApp
  class Application < Rails::Application
    config.autoload_paths << config.root.join('lib')
  end
end
# models/book.rb
class Book < ActiveRecord::Base
  belongs_to :shelf

  def shelf_name
    shelf.name
  end
end
# admin/books.rb
ActiveAdmin.register Book do
  index as: :grouped_table, group_by_attribute: :shelf_name do
    # columns
  end
end
# lib/active_admin/views/index_as_grouped_table.rb
require 'active_admin/views/index_as_table'

module ActiveAdmin
  module Views
    class IndexAsGroupedTable < IndexAsTable

      def build(page_presenter, collection)
        if group_by_attribute = page_presenter[:group_by_attribute]
          collection.group_by(&group_by_attribute).sort.each do |group_name, group_collection|
            h3 group_name
            super page_presenter, group_collection
          end
        else
          super
        end
      end

    end
  end
end

let me explain what the fuck happens in index_as_grouped_table.rb:

the class IndexAsGroupedTable extends ActiveAdmin's IndexAsTable class and overrides the build method to add grouping functionality. in your admin/books.rb file, in the index macro, you define an additional option :group_by_attribute which names the attribute name on the Book class by which to group. if that attribute is not provided, it falls back to IndexAsTable's behavior. if that attribute is provided, it'll group_by the collection by that attribute, sort the hash and run a block with each group_name and group_collection from that hash, printing an <h3> with the group_name and then just calls IndexAsTable's build method (super) to display the standard table.

as you see, only the groups are sorted and an h3 added to the page. everything else works like the standard index table.

note: this does not involve additional sql for the grouping. this uses ruby's group_by method of the Enumerable class. thus, it may be slow if you have many rows in the collection.

for the most current version and/or forks go to my my gist on github.

credits for the approach go to ariejan de vroom.

Upvotes: 7

James
James

Reputation: 774

Sounds like a job for a Custom Page

http://www.activeadmin.info/docs/10-custom-pages.html

  1. By passing ordered @books in Active Admin controller

  2. And then using table_for in content block (maybe a new table for each shelf? Or a shelf search field at the top. http://blog.agile-pandas.com/2011/07/06/activeadmin-beyond-the-basics

:)

Upvotes: 1

Related Questions