1

I am trying to export some data to CSV in Rails 4. I have two models: Excursions and Inscriptions. One excursion has many inscriptions and one inscription belongs to one excursion.

I have my nested routes defined this way:

  resources :excursions do
    resources :inscriptions
    get 'exportcsv' => 'excursions#download'
  end

So the behavior I am trying to achieve is: when I visit the route /excursions/1/exportcsv, a CSV will be downloaded to my computer and it will contain all the inscriptions with excursion_id = 1 in CSV format.

In my excursion model I have defined self.to_csv:

  def self.to_csv(options = {})
    CSV.generate(options) do |csv|
      csv << column_names
      self.inscriptions.each do |inscription|
        csv << inscription.attributes.values_at(*column_names)
      end
    end
  end

And my excursion controller's method download:

  def download
    @excursion = Excursion.find(params[:id])
    respond_to do |format|
      format.html
      format.csv { send_data @excursion.to_csv }
    end
  end

EDIT: When I go to a route like: /excursions/:id/exportcsv the server is throwing an ActiveRecord::RecordNotFound error. This error is easy to solve, but if I solve the RecordNotFound I get an ActionController::UnknownFormat in this line:

  def download
    @excursion = Excursion.find(params[:id])
    respond_to do |format|  ########THIS LINE
      format.html
      format.csv { send_data @excursion.to_csv }
    end
  end

What I am doing wrong? Maybe all this approach is not correct...

F404
  • 144
  • 1
  • 12

1 Answers1

0

I would update the routes to the following:

resources :excursions do
  get 'download', on: :member, constraints: { format: /(html|csv)/ }
  resources :inscriptions
end

Also there is a bug in your model code. You are exporting inscriptions but are using Excursion column_names instead of Inscription column_names. Following is the updated model code.

class Excursion < ActiveRecord::Base
  def to_csv(options = {})
    CSV.generate(options) do |csv|
    inscription_column_names = Inscription.column_names

    csv << inscription_column_names

    self.inscriptions.each do |inscription|
      csv << inscription.attributes.values_at(*inscription_column_names)
    end
  end
end

Now try to access http://localhost:3000/excursions/:id/download.csv

Replace :id with an existing Excursion records id. If you still encounter ActiveRecord::RecordNotFound error, then the problem could be that you are trying to access an Excursion that doesn't actually exist in the database.

Dharam Gollapudi
  • 6,328
  • 2
  • 34
  • 42
  • I have updated the code but now the servers is throwing an: *Missing template excursions/download, application/download with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}.* – F404 Mar 09 '16 at 22:14
  • 1
    Ok, I was missing the .csv extension. Anyway, now the server says that there is no method named to_csv: `undefined method 'to_csv' for # Did you mean? to_s` – F404 Mar 09 '16 at 22:17
  • Convert the class method `to_csv` to instance method `to_csv`. Updated the answer. – Dharam Gollapudi Mar 09 '16 at 22:20
  • Ups, sorry! My fault :) – F404 Mar 09 '16 at 22:44