CsvRails
CsvRails provides a simple way of download csv in Rails 3.
Supported versions
Ruby 1.9 (1.8 not supported) Rails 3 ActiveRecord or Mongoid
Install
To use CsvRails simply add the line
gem 'csv_rails'
to your Gemfile and then run
bundle install
Example
class UsersController < ApplicationController
def index
@users = User.all
respond_to do |format|
format.html { @users = @users.all }
format.json { render json: @users }
format.csv{ render csv: @users, fields: [:id, :name, :age], encoding: 'SJIS', without_header: true }
end
end
Usage
Download
If you want formatted attribute, CsvRails call “#attribute_as_csv”. For example, you wish formatted created_at then you write like this.
class User < ActiveRecord::Base
def created_at_as_csv
created_at.strftime("%F %H:%M")
end
end
CsvRails define a singleton method Array.to_csv, and the method accept fields option. The fields option can not only database fields also method and method chain.
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
def ok
"OK"
end
end
class UsersController < ApplicationController
def index
@users = User.all
respond_to do |format|
format.csv{ render csv: @users, fields: [:ok, :"groups.first.name"], encoding: 'SJIS' }
end
end
If you do not use :header option, header is using :fields and I18n transfer.
# config/locales/ja.yml
ja:
activerecord:
attributes:
group: &groupmodel
name: グループ名
user:
id: ID
name: 名前
age: 年齢
ok: OK
# rails3
groups:
first:
<<: *groupmodel
# rails 3.2.3 - 3.2.5
user/groups:
first:
<<: *groupmodel
# rails 3.2.6 or higher
groups/first:
<<: *groupmodel
# app/controllers/user_controller.rb
def index
@users = User.where("id < 1").all
respond_to do |format|
format.csv{ render csv: @users, fields: [:ok, :"groups.first.name"], encoding: 'SJIS' } #=> "OK,グループ名"
end
end
And you can use tsv. Both tsv and csv can accept row_sep option.
# app/controllers/user_controller.rb
def index
@users = User.all
respond_to do |format|
format.csv{ render csv: @users, :row_sep => "\r\n" }
format.tsv{ render tsv: @users, :row_sep => "\r\n" }
end
end
You also use i18n_scope option
# config/locales/ja.yml
ja:
csv:
name: なまえ
User.where("id < 1").all.to_csv(:i18n_scope => :csv) #=> "なまえ\n"
Upload
CSVRails is also have upload concern.
You should include CSVRails::Import into your model.
example
# app/model/user.rb
class User < ActiveRecord::Base
attr_accessor :file
include CsvRails::Import
....
And render file_field into form
example
# app/views/users/index.html.erb
<%= form_for(@user, multipart: true) do |f| %>
File: <%= f.file_field :file %>
<%= f.submit 'Upload' %>
<% end %>
Next implement action
# app/controllers/users_controller.rb
def create
if params[:format] == 'csv'
users = User.csv_import(params[:file])
if users.find{|u| u.errors.any? }
render :index
else
redirect_to users_path, notice: 'Upload success'
end
end
end
csv_import is be able to use block.
User.csv_import(params[:file]) do |user, params, row_number|
next false if row_number == 2 # 'next false' in the block, the line is skipped.
end
csv_import use transaction, if invalid line is existed then all rows is not imported.
First line used for fields, but you can manually choose it using options
User.csv_import(params[:file], fields: [:age, :name])
It line first line has ‘id’, csv_import call where(id: id).first_or_initialize, but you can use other field name
User.csv_import(params[:file], find_key: :name)
#=> It call User.where(name: name).first_or_initialize internal.
Copyright © 2012-2013 yalab, released under the MIT license