Question

I want to export a csv file from Rails and I'm following the Railscast on this topic (http://railscasts.com/episodes/362-exporting-csv-and-excel?view=asciicast).

In the Railscast, the controller (products_controller.rb) contains:

    def index
      @products = Product.order(:name)
      respond_to do |format|
        format.html
        format.csv { send_data @products.to_csv }
      end
    end

The Product model (models/product.rb) contains:

    def self.to_csv
      CSV.generate do |csv|
        csv << column_names
        all.each do |product|
          csv << product.attributes.values_at(*column_names)
        end
      end
    end

As seen in this StackOverflow question (Exporting CSV data from Rails), to_csv is a class method that is being called on an array of class objects. I expected this to fail because to_csv is not being called on the Product class.

This works, but why does it work?

Was it helpful?

Solution

My question should have been "Why would sending the message, to_csv, to an instance of ActiveRecord::Relation cause a method on the Product class object to be invoked?"

In Rails, class methods automatically become available as "collection" methods; This is the reason why they are available to Relation objects (See this SO question/answer I missed earlier: how does this Ruby class method get invoked?).

OTHER TIPS

You are indeed correct - you are sending the message to_csv to an instance of, initially ActiveRecord::Relation, which ultimately is transformed into Array.

Have you required csv? If so, sending to_csv to an instance of an Array will work.

The stdlib/csv library decorates Array - http://ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/Array.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top