Before, when attempting to download the CSV export of nodes and their resource statuses, the download wouldn't start until after all of the data had been collected, and converted to CSV.
By passing render a proc, and using output.write, we can send each CSV line to the client as it is generated. The main reason for doing this is to give the user immediate feedback that we recognize they clicked on the download link, instead of stalling until all of the data has been collected. This also should reduce the server-side memory footprint of the CSV, since we don't need to generate the entire CSV string in memory before sending it. Paired-with: Jacob Helwig <[email protected]> Signed-off-by: Nick Lewis <[email protected]> --- Local-branch: ticket/next/7007 app/controllers/nodes_controller.rb | 11 ++++++++++- spec/controllers/nodes_controller_spec.rb | 14 ++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb index 3e0f60d..ea79b72 100644 --- a/app/controllers/nodes_controller.rb +++ b/app/controllers/nodes_controller.rb @@ -123,7 +123,16 @@ class NodesController < InheritedResources::Base format.html { render :index } format.yaml { render :text => collection.to_yaml, :content_type => 'application/x-yaml' } - format.csv { render :text => collection.to_csv, :content_type => 'text/csv' } + format.csv do + response["Content-Type"] = 'text/comma-separated-values;' + response["Content-Disposition"] = 'filename="nodes.csv";' + + render :text => proc { |response,output| + collection.to_csv do |line| + output.write(line) + end + }, :layout => false + end end end end diff --git a/spec/controllers/nodes_controller_spec.rb b/spec/controllers/nodes_controller_spec.rb index f1d79f3..dadba2b 100644 --- a/spec/controllers/nodes_controller_spec.rb +++ b/spec/controllers/nodes_controller_spec.rb @@ -66,11 +66,17 @@ describe NodesController do 'change_count', 'out_of_sync_count', 'skipped', 'failed' ] end + def body_from_proc + body = StringIO.new + response.body.call(response, body) + body.string + end + it "should make correct CSV" do get :index, :format => "csv" response.should be_success - response.body.split("\n").should =~ [ + body_from_proc.split("\n").should =~ [ header, "#{@node.name},changed,1,0,0,1,#{@resource.resource_type},#{@resource.title},#{@resource.evaluation_time},#{@resource.file},#{@resource.line},#{@resource.time},#{@resource.change_count},#{@resource.out_of_sync_count},#{@resource.skipped},#{@resource.failed}" ] @@ -83,7 +89,7 @@ describe NodesController do get :index, :format => "csv" response.should be_success - response.body.split("\n").should =~ [ + body_from_proc.split("\n").should =~ [ header, "#{@node.name},changed,1,0,0,1,#{@resource.resource_type},#{@resource.title},#{@resource.evaluation_time},#{@resource.file},#{@resource.line},#{@resource.time},#{@resource.change_count},#{@resource.out_of_sync_count},#{@resource.skipped},#{@resource.failed}", "#{unreported_node.name},,,,,,,,,,,,,,," @@ -97,7 +103,7 @@ describe NodesController do get :index, :format => "csv" response.should be_success - CSV.parse(response.body).last.first.should == name + CSV.parse(body_from_proc).last.first.should == name end end @@ -123,7 +129,7 @@ describe NodesController do get :index, :format => "csv" response.should be_success - response.body.split("\n").should =~ [ + body_from_proc.split("\n").should =~ [ header, %Q[#{@node.name},failed,2,0,1,1,File,/etc/sudoers,1.0,/etc/puppet/manifests/site.pp,1,#{res1.time},1,1,false,false], %Q[#{@node.name},failed,2,0,1,1,File,/etc/hosts,2.0,/etc/puppet/manifests/site.pp,5,#{res2.time},2,2,false,true] -- 1.7.5.1 -- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
