Reputation: 393
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
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 theEnumerable
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
Reputation: 774
Sounds like a job for a Custom Page
http://www.activeadmin.info/docs/10-custom-pages.html
By passing ordered @books in Active Admin controller
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