Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/documents export #43

Merged
merged 9 commits into from
Aug 30, 2019
37 changes: 36 additions & 1 deletion app/admin/documents.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,44 @@
actions
end

csv do
column :id
column :name
column :external_url
column :language
column :last_verified_on
column 'Documentable ID', &:documentable_id
column :documentable_type
end

controller do
def scoped_collection
super.includes(:documentable)
results = super.includes(:documentable)

documentable_klass = find_documentable_klass

if documentable_klass.present? && documentable_params.present?
results = results.where(
documentable: documentable_klass.ransack(documentable_params).result
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tsubik thanks for improving this! works like a charm now)

)
end

results
end

private

def find_documentable_klass
documentable_type = params.dig(:q, :documentable_type_eq)
return nil unless documentable_type

documentable_type.constantize
rescue NameError => e
raise "Can't find documentable class based on given 'documentable_type_eq' param: #{e.message}"
end

def documentable_params
@documentable_params ||= params.dig(:q, :documentable)
end
end
end
2 changes: 1 addition & 1 deletion app/admin/legislations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

publishable_sidebar only: :show

data_export_sidebar 'Legislations'
data_export_sidebar 'Legislations', documents: true

show do
tabs do
Expand Down
2 changes: 1 addition & 1 deletion app/admin/litigations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
array_to_select_collection(Litigation::DOCUMENT_TYPES)
}

data_export_sidebar 'Litigations'
data_export_sidebar 'Litigations', documents: true

index do
column :title, class: 'max-width-300', &:title_link
Expand Down
25 changes: 21 additions & 4 deletions lib/extensions/active_admin/active_admin_csv_download.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
module ActiveAdminCsvDownload
#
# Generates Export Data sidebar section
# - based on <sidebar_if_proc>
# - generates CSV download links
# Generates Export Data sidebar section.
#
def data_export_sidebar(resource_name)
# Sidebar contains CSV download links to:
# - current resource list
# - related Documents list (optional, if :documents option is passed)
#
def data_export_sidebar(resource_name, options = {})
documents_export_link = options.fetch(:documents) { false }

sidebar 'Export data', if: -> { collection.any? }, only: :index do
ul do
li do
Expand All @@ -14,6 +18,19 @@ def data_export_sidebar(resource_name)
format: 'csv'
)
end

if documents_export_link
li do
a 'Download related Documents CSV',
href: admin_documents_path(
format: 'csv',
q: {
documentable_type_eq: resource_name.singularize,
documentable: request.query_parameters[:q]
}
)
end
end
end
hr
end
Expand Down
95 changes: 93 additions & 2 deletions spec/controllers/admin/documents_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
require 'rails_helper'
require 'csv'

RSpec.describe Admin::DocumentsController, type: :controller do
let(:admin) { create(:admin_user) }
let!(:document) { create(:document) }
let!(:legislation1) { create(:legislation, visibility_status: 'published') }
let!(:legislation2) { create(:legislation, visibility_status: 'pending') }
let!(:litigation1) { create(:litigation, visibility_status: 'published') }
let!(:litigation2) { create(:litigation, visibility_status: 'draft') }

let!(:document1) { create(:document, name: 'Doc1', documentable: legislation1) } # with published documentable
let!(:document2) { create(:document, name: 'Doc2', documentable: legislation2) }
let!(:document3) { create(:document, name: 'Doc3', documentable: litigation1) } # with published documentable
let!(:document4) { create(:document, name: 'Doc4', documentable: litigation2) }

before { sign_in admin }

Expand All @@ -12,9 +21,91 @@
it { is_expected.to be_successful }
end

describe 'GET index with .csv format' do
before :each do
get :index, format: 'csv'
end

it('returns CSV file') do
expect(response.header['Content-Type']).to include('text/csv')
end

it('returns all documents') do
csv = response_as_csv

expect(csv.by_col[1].sort).to eq(%w[Doc1 Doc2 Doc3 Doc4])
end
end

describe 'GET index with .csv format (query, results present)' do
before :each do
get :index,
params: {
q: {
# should narrow down results to 'Doc1'
documentable: {visibility_status_eq: 'published'},
documentable_type_eq: 'Legislation'
}
},
format: 'csv'
end

it('returns CSV file') do
expect(response.header['Content-Type']).to include('text/csv')
end

it('returns filtered documents list') do
csv = response_as_csv

# returned CSV must contain only result row + header
expect(csv.to_a.size).to eq(2)

# check filtered data
expect(csv[0]['Name']).to eq('Doc1')
expect(csv[0]['Documentable type']).to eq('Legislation')

# only single data row
expect(csv[1]).to be_nil
end
end

describe 'GET index with .csv format (query, no results)' do
before :each do
get :index,
params: {
q: {
# should return no results for that query!
documentable: {visibility_status_eq: 'pending'},
documentable_type_eq: 'Litigation'
}
},
format: 'csv'
end

it('returns CSV file') do
expect(response.header['Content-Type']).to include('text/csv')
end

it('returns empty CSV file (only header)') do
csv = response_as_csv

# only header expected
expected_columns = [
'Id', 'Name', 'External url',
'Language', 'Last verified on',
'Documentable id', 'Documentable type'
]
expect(csv.to_a).to eq([expected_columns])
end
end

describe 'GET show' do
subject { get :show, params: {id: document.id} }
subject { get :show, params: {id: document1.id} }

it { is_expected.to be_successful }
end

def response_as_csv
CSV.parse(response.body, headers: true)
end
end