Skip to content

Commit

Permalink
CSV is now customizable
Browse files Browse the repository at this point in the history
  • Loading branch information
pcreux committed May 31, 2011
1 parent ccd8bf5 commit 7097470
Show file tree
Hide file tree
Showing 18 changed files with 239 additions and 171 deletions.
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -30,6 +30,7 @@ gem 'formtastic', '>= 1.1.0'
gem 'will_paginate', '>= 3.0.pre2'
gem 'inherited_resources'
gem 'sass', '>= 3.1.0'
gem 'fastercsv', :platforms => :ruby_18

group :development, :test do
gem 'sqlite3-ruby', :require => 'sqlite3'
Expand Down
9 changes: 9 additions & 0 deletions README.rdoc
Expand Up @@ -291,6 +291,15 @@ the collection as a proc to be called at render time.
# Will call available
filter :author, :as => :check_boxes, :collection => proc { Author.all }

== Customizing the CSV format

Customizing the CSV format is as simple as customizing the index page.

csv do
column :name
column("Author") { |post| post.author.full_name }
end

== Customizing the Form

Active Admin gives complete control over the output of the form by creating a thin DSL on top of
Expand Down
2 changes: 1 addition & 1 deletion features/comments/commenting.feature
Expand Up @@ -81,5 +81,5 @@ Feature: Commenting
Scenario: Viewing all commments for a namespace
When I add a comment "Hello from Comment"
When I am on the index page for comments
Then I should see a table header for "Body"
Then I should see a table header with "Body"
And I should see "Hello from Comment"
20 changes: 17 additions & 3 deletions features/index/format_as_csv.feature
Expand Up @@ -9,10 +9,24 @@ Feature: Format as CSV
When I am on the index page for posts
And I follow "CSV"
Then I should see the CSV:
| ID | Title | Body | Published At | Created At | Updated At |
| Id | Title | Body | Published At | Created At | Updated At |
| \d+ | Hello World | | | (.*) | (.*) |

Scenario: With index customization

Scenario: With CSV format customization
Given an index configuration of:
"""
ActiveAdmin.register Post do
csv do
column :title
column("Last update") { |post| post.updated_at }
column("Copyright") { "Greg Bell" }
end
end
"""
And a post with the title "Hello World" exists
When I am on the index page for posts
And I follow "CSV"
Then I should see the CSV:
| Title | Last update | Copyright |
| Hello World | (.*) | Greg Bell |

26 changes: 18 additions & 8 deletions features/step_definitions/format_steps.rb
Expand Up @@ -6,14 +6,24 @@
Then %{I should see "#{format_type}" within "#index_footer a"}
end

require 'csv'

Then /^I should see the CSV:$/ do |table|
puts page.body
csv = CSV.parse(page.body)
csv.each_with_index do |row, row_index|
row.each_with_index do |cell, col_index|
cell.should match(/#{table.raw[row_index][col_index]}/)
end
begin
csv = CSV.parse(page.body)
csv.each_with_index do |row, row_index|
row.each_with_index do |cell, col_index|
expected_cell = table.raw.try(:[], row_index).try(:[], col_index)
if expected_cell.blank?
cell.should be_nil
else
cell.should match(/#{expected_cell}/)
end
end
end
rescue
puts "Expecting:"
p table.raw
puts "to match:"
p csv
raise $!
end
end
2 changes: 1 addition & 1 deletion lib/active_admin.rb
Expand Up @@ -13,6 +13,7 @@ module ActiveAdmin
autoload :Callbacks, 'active_admin/callbacks'
autoload :Component, 'active_admin/component'
autoload :ControllerAction, 'active_admin/controller_action'
autoload :CSVBuilder, 'active_admin/csv_builder'
autoload :Dashboards, 'active_admin/dashboards'
autoload :Devise, 'active_admin/devise'
autoload :DSL, 'active_admin/dsl'
Expand All @@ -29,7 +30,6 @@ module ActiveAdmin
autoload :Scope, 'active_admin/scope'
autoload :Sidebar, 'active_admin/sidebar'
autoload :TableBuilder, 'active_admin/table_builder'
autoload :TableToCSV, 'active_admin/table_to_csv'
autoload :ViewFactory, 'active_admin/view_factory'
autoload :ViewHelpers, 'active_admin/view_helpers'
autoload :Views, 'active_admin/views'
Expand Down
45 changes: 45 additions & 0 deletions lib/active_admin/csv_builder.rb
@@ -0,0 +1,45 @@
module ActiveAdmin
# CSVBuilder stores CSV configuration
#
# Usage example:
#
# csv_builder = CSVBuilder.new
# csv_builder.column :id
# csv_builder.column("Name") { |resource| resource.full_name }
#
class CSVBuilder

# Return a default CSVBuilder for a resource
# The CSVBuilder's columns would be Id followed by this
# resource's content columns
def self.default_for_resource(resource)
new.tap do |csv_builder|
csv_builder.column(:id)
resource.content_columns.each do |content_column|
csv_builder.column(content_column.name.to_sym)
end
end
end

attr_reader :columns

def initialize(&block)
@columns = []
instance_eval &block if block_given?
end

# Add a column
def column(name, &block)
@columns << Column.new(name, block)
end

class Column
attr_reader :name, :data

def initialize(name, block = nil)
@name = name.is_a?(Symbol) ? name.to_s.titleize : name
@data = block || name.to_sym
end
end
end
end
13 changes: 13 additions & 0 deletions lib/active_admin/dsl.rb
Expand Up @@ -115,6 +115,19 @@ def form(options = {}, &block)
controller.form_config = options
end

# Configure the CSV format
#
# For example:
#
# csv do
# column :name
# column("Author") { |post| post.author.full_name }
# end
#
def csv(&block)
config.csv_builder = CSVBuilder.new(&block)
end

# Member Actions give you the functionality of defining both the
# action and the route directly from your ActiveAdmin registration
# block.
Expand Down
14 changes: 12 additions & 2 deletions lib/active_admin/resource.rb
Expand Up @@ -46,6 +46,8 @@ class Resource
# Set to false to turn off admin notes
attr_accessor :admin_notes

# Set the configuration for the CSV
attr_writer :csv_builder

def initialize(namespace, resource, options = {})
@namespace = namespace
Expand Down Expand Up @@ -189,6 +191,11 @@ def belongs_to?
!belongs_to_config.nil?
end

# The csv builder for this resource
def csv_builder
@csv_builder || default_csv_builder
end

private

def default_options
Expand All @@ -198,5 +205,8 @@ def default_options
}
end

end
end
def default_csv_builder
@default_csv_builder ||= CSVBuilder.default_for_resource(resource)
end
end # class Resource
end # module ActiveAdmin
9 changes: 0 additions & 9 deletions lib/active_admin/resource_controller.rb
Expand Up @@ -21,7 +21,6 @@ class ResourceController < ::InheritedResources::Base

before_filter :only_render_implemented_actions
before_filter :authenticate_active_admin_user
before_filter :prepare_csv_columns, :only => :index

include ActiveAdmin::ActionItems
include ActionBuilder
Expand Down Expand Up @@ -116,13 +115,5 @@ def renderer_for(action)
ActiveAdmin.view_factory["#{action}_page"]
end
helper_method :renderer_for

# Before filter to prepare the columns for CSV. Note this will
# be deprecated very soon.
def prepare_csv_columns
if request.format.csv?
@csv_columns = resource_class.columns.collect{ |column| column.name.to_sym }
end
end
end
end
44 changes: 0 additions & 44 deletions lib/active_admin/table_to_csv.rb

This file was deleted.

17 changes: 8 additions & 9 deletions lib/active_admin/views/pages/index.rb
Expand Up @@ -26,6 +26,14 @@ def main_content
end
end

protected

def build_scopes
if active_admin_config.scopes.any?
scopes_renderer active_admin_config.scopes
end
end

# Creates a default configuration for the resource class. This is a table
# with each column displayed as well as all the default actions
def default_index_config
Expand All @@ -38,15 +46,6 @@ def default_index_config
end
end

protected

def build_scopes
if active_admin_config.scopes.any?
scopes_renderer active_admin_config.scopes
end
end


# Returns the actual class for renderering the main content on the index
# page. To set this, use the :as option in the page_config block.
def find_index_renderer_class(symbol_or_class)
Expand Down
@@ -1,2 +1,15 @@
<%= @csv_columns.collect{|c| c.to_s.titleize }.join(",").html_safe %>
<%= collection.collect{|resource| @csv_columns.collect{|col| "\"#{resource.send(col).to_s.gsub('"', '""')}\""}.join(",") }.join("\n").html_safe %>
<%-
# FasterCSV is CSV in ruby1.9
csv_lib = defined?(FasterCSV) ? FasterCSV : CSV

csv_output = csv_lib.generate do |csv|
columns = active_admin_config.csv_builder.columns
csv << columns.map(&:name)
collection.each do |resource|
csv << columns.map do |column|
call_method_or_proc_on resource, column.data
end
end
end
%>
<%= csv_output %>

This file was deleted.

35 changes: 0 additions & 35 deletions spec/controllers/index_as_csv_spec.rb

This file was deleted.

0 comments on commit 7097470

Please sign in to comment.