Exporting records to csv in Rails

It’s common to want to export data from a Web application in CSV or Excel format and in this post, I’ll show how to do that in a Rails application. Below is a page that shows a list of users of the application and we’d like to add some links to allow this list to be downloaded as a CSV or Excel file.

Screen Shot 2016-08-21 at 9.15.26 PM

There are many gems that can help us to do this but we won’t be using any of them here and this is quite easy to write from scratch.

Exporting to CSV

Ruby comes with an excellent CSV library that was formerly known as Faster CSV in Ruby 1.8. We’ll use this library to generate our CSV data. As it’s part of the standard library all we have to do is require it and we’ll do this in our application’s config file.

In /config/application.rb, add => require “csv”

require File.expand_path('../boot', __FILE__)

require "csv"
require "rails"

In this example, we want to download the users records in a csv format.

In the controller:/app/controllers/users_controller.rb, add the following line to the index action: The "users-#{Date.today}.csv"allows you name the file path in such a way that the date downloaded is recorded. Feel free to customize it the way you want.

class UsersController < ApplicationController
  def index
    @users = User.all.order(:id)
    respond_to do |format|
      format.html
      format.csv { send_data @users.to_csv, filename: "users-#{Date.today}.csv" }
    end
  end
end

In /app/models/user.rb

We’ll generate the CSV data in the User model in a new to_csv method.

class Product < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  
  def self.to_csv
    CSV.generate do |csv|
      csv << %w{ id email score } 
      all.each do |user|
        csv << [user.id, user.email, user.score ) ]
      end
    end
  end

end

The next step is to insert a line of code in our view. In this scenario, my view code is in app/views/users/index.html.erb

<div class="well users-table">
  <table class="table">
    <h5 style="text-align: center">Users list</h5>
    <thead>
    <tr>
      <th>ID</th>
      <th>Email</th>
      <th>Score</th>
    </tr>
    </thead>
    <tbody>
    <% @users.each do |user| %>
    <tr>
      <td><%= user._id %></td>
      <td><%= user.email %></td>
      <td><%= user.score %></td>
    </tr>
    <% end %>
    </tbody>
  </table>
  <p><%= link_to("Generate Report", users_path(format: :csv), class: "btn btn-success",) %></p>
</div>

This line <p><%= link_to("Generate Report", users_path(format: :csv), class: "btn btn-success",) %></p>  generates a button like this:

Screen Shot 2016-08-21 at 9.39.35 PM

When the button is clicked, it downloads the records in csv. Voila, we don’t need a gem for it. The method described above is for a download of general collection. What if we need to download for a particular user detail? For example,

localhost:8000/users/2

This means we have a view for a particular user and we want to export their date in csv. Be my guest as I guide you through:

In the controller:/app/controllers/users_controller.rb, add the following line to the show action:

def show
   @user = User.find(params[:id])
   respond_to do |format|
       format.html
       format.csv { send_data @user.csv, filename: "#{@user.email}-donations-#{Date.today}.csv" }
   end
 end

In the model: /app/models/user.rb

def csv
   CSV.generate do |csv|
     csv << %w{ user_id user_email user_score }
     csv << [ self.id, self.email, self.score]
   end
 end

In the view, show.html.erb – we add this likewise:

<div class="container">
  <div class="row col-md-6 col-md-offset-2 custyle">
    <table class="table table-striped custab">
      <thead>
      <tr>
        <th>ID</th>
        <th>Email</th>
        <th>Score</th>
      </tr>
      </thead>
      <tr>
        <td><%= @user._id %></td>
        <td><%= @user.email %></td>
        <td><%= @user.score %></td>
      </tr>
      <p><%= link_to("Generate Report", users_path(@user, format: :csv), class: "btn btn-success",) %></p>
    </table>
  </div>

</div>

This will be the end of this tutorial. This same technique can work for exporting records in models with complex associations. Thanks for reading and please do not hesitate to post questions, suggestions, code review :) , etc.

 

You may also like

Leave a Reply

Your email address will not be published. Required fields are marked *