ActiveAdmin is great framework for managing website administration interfaces. It allows us to list records of a table, filter them, sort them and also support exporting them in CSV, XML or JSON. By default, records that are being displayed are exported. For example, say we have a products
table where each product is distinguished by their type
. We can apply a filter to list all electronics products. Clicking on CSV
link below the list will export all electronics products only.
But sometimes we need to download specific records coming from a custom query or scope using the default csv
link. For example, its not possible to filter out electronics and fashion products
both. In this case, you would need query or a scope that can filter the records. To export the records, we need to override default index
action.
In admin/product.rb
-
controller do
def index
index! do |format|
@products = Product.custom_query # or scope
format.html
format.csv { export_csv @products }
format.json { render json: @products }
format.xml { render xml: @products }
end
end
end
Next, we need to add export_csv
method which we used above when request format is csv
. We can add this in Admin::ProductsController
buts its good to add it at a place where it can be used by other admin controllers as well. ActiveAdmin gem has a module Streaming
which has method export_csv
(same method name but without arguments). We will override this method. Also, note the last line of export_csv
method creates a block using self
which is an object of controller that accepts the request of downloading CSV. To override the existing export functionality, we need to pass a custom controller (I have named it as DummyController
) object that holds the records that are generated by custom query/scope.
In config/initializers/active_admin.rb
-
class ActiveAdmin::ResourceController
module Streaming
class DummyController
def initialize(collection:)
@collection = collection
end
attr_reader :collection
end
def export_csv(collection)
controller = DummyController.new(collection: collection)
headers['Content-Disposition'] = %{attachment; filename="#{csv_filename}"}
stream_resource &active_admin_config.csv_builder.method(:build).to_proc.curry[controller]
end
end
end
We are not done yet. When we try to download CSV using above code it will give an error -
NoMethodError (undefined method 'find_collection' for #<ActiveAdmin::ResourceController::Streaming::DummyController>)
Before we add find_collection
method to DummyController
to fix above error, lets check out build
method here under CSVBuilder
class which is called from the block we created above in export_csv
method (active_admin_config.csv_builder.method(:build)
). The build
method iterates over the collection and prepares the CSV. If we look closer in that method, there are three methods that are called from controller
object - find_collection
, view_context
and apply_decorator
. We need to add all three the methods in DummyController
.
class ActiveAdmin::ResourceController
module Streaming
class DummyController
def initialize(collection:)
@collection = collection
end
attr_reader :collection
def find_collection(*)
collection
end
def apply_decorator(resource)
resource
end
def view_context
@view_context ||= ViewContext.new
end
class ViewContext
include MethodOrProcHelper
end
end
def export_csv(collection)
controller = DummyController.new(collection: collection)
headers['Content-Disposition'] = %{attachment; filename="#{csv_filename}"}
stream_resource &active_admin_config.csv_builder.method(:build).to_proc.curry[controller]
end
end
end
Now you can download records from a custom query or scope in CSV format.
Note: This code snippet has been tested in Rails 5.0
app having active_admin
gem locked at version 1.0.0.pre4
. This might or might not work in earlier or newer versions of active_admin
gem.