lost password?

home
•  reviewramp
•  rails +
•  javascript
•  webdev
•  django
•  xaraya
•  xamp
•  musings

rss
Tag this page
   

» Blogs that link here
last modified: Dec 03, 2009
(first posted: Dec 03, 2009)
(407 Reads)
Permalink

Export to CSV and "ArgumentError: A copy of SubmissionsController has been removed from the module tree but is still active!"

For a long time my SubmissionsController #export action seemed to work just fine. Until earlier today, I noticed it wasn't working. Looking in the logs it reported

ArgumentError: A copy of SubmissionsController has been removed from the module tree but is still active!

 The export to CSV is implemented using faster_csv gem (1.5.0) and the stream_csv method as described originally in http://oldwiki.rubyonrails.org/rails/pages/HowtoExportDataAsCSV and also found among other places here .

And it worked fine. Or so I thought. I upgraded my app from Rails 2.0 to 2.3 about 6 months ago. Has it been broken that long? well, the problem never showed up in my rspec tests and I guess I haven't clicked through this feature in the browser recently.

So I googled the error and found several posts related to Rails engines and/or modules and/or plugins where one module stays in memory and another is getting unloaded. It may only be an issue when running in development mode, i didnt really verify that; should have, but instead i kept tweaking the code to see if this change or that would make the problem go away.

Per the original examples my controller does something like this:

def export_users
  users = User.find(:all)
    stream_csv do |csv|
      csv << ["first","last","id","email"]
      users.each do |u|
        csv << [u.first,u.last,u.id,u.email]
      end
    end
  end

I had moved the stream_csv into its own module in lib/stream_csv.rb, something like this:

module StreamCsv
  def stream_csv( basename, &block )
     filename = basename + ".csv"   
    
     #this is required if you want this to work with IE       
     if request.env['HTTP_USER_AGENT'] =~ /msie/i
       headers['Pragma'] = 'public'
       headers["Content-type"] = "text/plain"
       headers['Cache-Control'] = 'no-cache, must-revalidate, post-check=0, pre-check=0'
       #If the above doesn’t work for you, try setting Cache-Control to private
       #headers['Cache-Control'] = 'private'
       headers['Content-Disposition'] = "attachment; filename=\"#{filename}\""
       headers['Expires'] = "0"
     else
       headers["Content-Type"] ||= 'text/csv'
       headers["Content-Disposition"] = "attachment; filename=\"#{filename}\""
     end
 
    render :text => Proc.new { |response, output|
      csv = FasterCSV.new(output, :row_sep => "\r\n")
      yield csv
    }

  end
end

 

The short of it is, I had to modify the implementation of stream_csv so the render uses FasterCSV.generate and send_data like this:

 

     content = FasterCSV.generate( :row_sep => "\r\n" ) do |csv|
       yield csv
     end
     
     send_data content, :filename => filename

 

Voila! The error goes away. I'm happy. And stupid. Because I really don't know why it's ok now. Anyone want to explain?

Meanwhile, there are newer solutions to generating CSV which are cleaner altogether and move more code out of the controller, I'll probably use on my next projects. For example, See http://rubyrailsandwindows.blogspot.com/2009/06/rails-view-export-to-csv.html

 

 

There are no comments attached to this item.

Post a new comment

How many days in a week?

Name :