csv_rails 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -21,19 +21,63 @@ to your Gemfile and then run
21
21
  respond_to do |format|
22
22
  format.html { @users = @users.all }
23
23
  format.json { render json: @users }
24
- format.csv{ render csv: @users, :fields => [:id, :name, :age], :encoding => 'SJIS' }
24
+ format.csv{ render csv: @users, fields: [:id, :name, :age], encoding: 'SJIS', without_header: true }
25
25
  end
26
26
  end
27
27
 
28
28
 
29
29
  == Usage
30
30
 
31
- If you want formatted created_at in the csv you should write like this
31
+ If you want formatted attribute, CsvRails call "#{attribute}_as_csv". For example, you wish formatted created_at then you write like this.
32
32
 
33
33
  class User < ActiveRecord::Base
34
34
  def created_at_as_csv
35
35
  created_at.strftime("%F %H:%M")
36
36
  end
37
37
  end
38
-
38
+
39
+ 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.
40
+
41
+ class User < ActiveRecord::Base
42
+ has_many :memberships
43
+ has_many :groups, through: :memberships
44
+
45
+ def ok
46
+ "OK"
47
+ end
48
+ end
49
+
50
+ class UsersController < ApplicationController
51
+ def index
52
+ @users = User.all
53
+
54
+ respond_to do |format|
55
+ format.csv{ render csv: @users, fields: [:ok, :"groups.first.name"], encoding: 'SJIS' }
56
+ end
57
+ end
58
+
59
+ If you do not use :header option, header is using :fields and I18n transfer.
60
+ # config/locales/ja.yml
61
+ ja:
62
+ activerecord:
63
+ attributes:
64
+ group: &groupmodel
65
+ name: グループ名
66
+ user:
67
+ id: ID
68
+ name: 名前
69
+ age: 年齢
70
+ ok: OK
71
+ groups:
72
+ first:
73
+ <<: *groupmodel
74
+
75
+ # app/controllers/user_controller.rb
76
+ def index
77
+ @users = User.where("id < 1").all
78
+ respond_to do |format|
79
+ format.csv{ render csv: @users, fields: [:ok, :"groups.first.name"], encoding: 'SJIS' } #=> "OK,グループ名"
80
+ end
81
+ end
82
+
39
83
  Copyright (c) 2012 yalab, released under the MIT license
@@ -0,0 +1,44 @@
1
+ require 'csv'
2
+ module CsvRails
3
+ module ActiveRecord
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ ::ActiveRecord::Relation.send(:include, ClassMethods)
7
+ base.send(:include, InstanceMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def to_csv(opts={})
12
+ fields = if opts[:fields]
13
+ opts.delete(:fields)
14
+ elsif respond_to?(:attribute_names)
15
+ attribute_names
16
+ elsif self.is_a?(::ActiveRecord::Relation)
17
+ @klass.new.attribute_names
18
+ else
19
+ new.attribute_names
20
+ end
21
+ header = fields.map{|f| human_attribute_name(f) }
22
+ all.to_csv(opts.update(:fields => fields, :header => header))
23
+ end
24
+
25
+ def csv_header(names)
26
+ names.map{|n| human_attribute_name(n) }
27
+ end
28
+ end
29
+
30
+ module InstanceMethods
31
+ def to_csv_ary(fields=nil, opts={})
32
+ fields = attribute_names unless fields
33
+ fields.map{|field|
34
+ field.to_s.split(".").inject(self){|object, f|
35
+ next unless object
36
+ convert_method = "#{f}_as_csv"
37
+ method = respond_to?(convert_method) ? convert_method : f
38
+ object.send(f)
39
+ }
40
+ }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -7,20 +7,24 @@ module CsvRails
7
7
  end
8
8
 
9
9
  module InstanceMethods
10
+ # ==== Options
11
+ # * <tt>:fields</tt> - target field names
12
+ # * <tt>:header</tt> - header
13
+ # * <tt>:without_header</tt> - total_count
14
+ # * <tt>:encoding</tt> - encoding
10
15
  def to_csv(opts={})
11
- return "" if length < 1
12
- first = self.first
13
- fields = opts.delete(:fields) || first.class.attribute_names
16
+ fields = opts[:fields]
17
+ header = if opts[:header]
18
+ opts.delete(:header)
19
+ elsif (klass = first.class).respond_to?(:csv_header)
20
+ klass.csv_header(fields)
21
+ else
22
+ fields
23
+ end
14
24
  csv = CSV.generate do |_csv|
15
- unless opts[:without_header]
16
- _csv << if first.class.respond_to?(:human_attribute_name)
17
- fields.map{|f| first.class.human_attribute_name(f) }
18
- else
19
- fields
20
- end
21
- end
25
+ _csv << header unless opts[:without_header]
22
26
  each do |element|
23
- _csv << element.to_csv_ary(fields, opts)
27
+ _csv << element.to_csv_ary(fields, opts)
24
28
  end
25
29
  end
26
30
  opts[:encoding] ? csv.encode(opts[:encoding]) : csv
@@ -1,3 +1,3 @@
1
1
  module CsvRails
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/csv_rails.rb CHANGED
@@ -1,6 +1,7 @@
1
- require File.expand_path('../active_record/acts/csv', __FILE__)
2
- require File.expand_path('../csv_rails/array', __FILE__)
3
- ActiveRecord::Base.send(:include, ActiveRecord::Acts::Csv)
1
+ require 'csv_rails/array'
2
+ require 'csv_rails/active_record'
3
+
4
+ ActiveRecord::Base.send(:include, CsvRails::ActiveRecord)
4
5
  Array.send(:include, CsvRails::Array)
5
6
 
6
7
  ActionController::Renderers.add :csv do |obj, options|
@@ -0,0 +1,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+ class CsvRails::ActiveRecordTest < ActiveSupport::TestCase
4
+ setup do
5
+ @user = User.create(:name => 'yalab', :age => '29', :secret => 'password')
6
+ @group = Group.create(:name => 'ruby')
7
+ @user.groups << @group
8
+ end
9
+
10
+ test "#to_csv_ary without params" do
11
+ assert_equal @user.attributes.length, @user.to_csv_ary.length
12
+ assert_equal @user.attributes.values[0..-2], @user.to_csv_ary[0..-2]
13
+ end
14
+
15
+ test "#to_csv_ary with field params" do
16
+ fields = [:name, :age]
17
+ assert_equal fields.map{|f| @user[f] }, @user.to_csv_ary(fields)
18
+ end
19
+
20
+ test "#to_csv_ary use method not a database field" do
21
+ assert_equal [@user.one], @user.to_csv_ary([:one])
22
+ end
23
+
24
+ test "#to_csv_ary can use association" do
25
+ assert_equal [@user.name, @group.name], @user.memberships.first.to_csv_ary([:"user.name", :"group.name"])
26
+ end
27
+
28
+ test "#to_csv_ary ignore empty association" do
29
+ name = 'noman'
30
+ assert_equal [name, nil], User.new(:name => 'noman').to_csv_ary([:name, :"groups.first.name"])
31
+ end
32
+
33
+ test "#updated_at_as_csv" do
34
+ assert_equal @user.updated_at.strftime("%F %H:%M"), @user.updated_at_as_csv
35
+ end
36
+
37
+ test ".to_csv without params" do
38
+ csv = CSV.parse(User.to_csv)
39
+ header = csv.first.map{|f| f.downcase.tr(' ', '_') }
40
+ header.delete("updated_at")
41
+ line = csv.last
42
+ header.each.with_index do |field, index|
43
+ assert_equal @user[field].to_s, line[index]
44
+ end
45
+ end
46
+
47
+ test ".to_csv can use fields option" do
48
+ fields = [:id, :name]
49
+ row = CSV.parse(User.to_csv(:fields => fields)).last
50
+ assert_equal fields.map{|f| @user[f].to_s }, row
51
+ end
52
+
53
+ test ".to_csv without_header" do
54
+ fields = [:id, :name]
55
+ row = CSV.parse(User.to_csv(:fields => fields, :without_header => true)).first
56
+ assert_not_equal fields.map{|f| User.human_attribute_name(f) }, row
57
+ end
58
+
59
+ test ".to_csv header use human_attribute_name" do
60
+ fields = [:id, :name, :one]
61
+ header = CSV.parse(User.to_csv(:fields => fields)).first
62
+ assert_equal fields.map{|f| User.human_attribute_name(f) }, header
63
+ end
64
+
65
+ test ".to_csv with scoped" do
66
+ User.create(:name => 'atsushi', :age => 45, :secret => 'none')
67
+ assert_equal 1, CSV.parse(User.where("age > 39").to_csv(:without_header => true)).length
68
+ end
69
+
70
+ test ".to_csv accept encoding" do
71
+ I18n.locale = :ja
72
+ assert_equal "名前".encode('SJIS'), CSV.parse(User.to_csv(:fields => [:name], :encoding => 'SJIS')).first.first
73
+ I18n.locale = :en
74
+ end
75
+
76
+ test ".csv_header with association" do
77
+ I18n.locale = :ja
78
+ assert_equal [User.human_attribute_name(:name), Group.human_attribute_name(:name)], User.csv_header([:name, :"groups.first.name"])
79
+ I18n.locale = :en
80
+ end
81
+
82
+ test ".to_csv with association" do
83
+ I18n.locale = :ja
84
+ csv =<<-EOS.gsub(/^\s+/, '')
85
+ #{User.human_attribute_name(:name)},#{Group.human_attribute_name(:name)}
86
+ #{@user.name},#{@group.name}
87
+ EOS
88
+ assert_equal csv, User.includes(:groups).to_csv(:fields => [:name, :"groups.first.name"])
89
+ I18n.locale = :en
90
+ end
91
+ end
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class CsvRails::ArrayTest < ActiveSupport::TestCase
5
+ test ".to_csv with header option" do
6
+ header = ['foo', 'bar']
7
+ assert_equal header.join(','), [].to_csv(:header => header).chomp
8
+ end
9
+
10
+ test ".to_csv accept encoding" do
11
+ name = "名前"
12
+ assert_equal name.encode('SJIS'), [].to_csv(:header => [name], :encoding => 'SJIS').chomp
13
+ end
14
+ end
@@ -1,17 +1,17 @@
1
1
  class UsersController < ApplicationController
2
2
  def index
3
- @users = User
3
+ @users = User.includes(:groups)
4
4
  respond_to do |format|
5
5
  format.html
6
- format.csv { render csv: @users, fields: [:id, :name, :age] }
6
+ format.csv { render csv: @users, fields: [:id, :name, :age, :"groups.first.name"], without_header: true }
7
7
  end
8
8
  end
9
9
 
10
10
  def sjis
11
- @users = User.all
11
+ @users = User.includes(:groups).all
12
12
  respond_to do |format|
13
13
  format.html
14
- format.csv { render csv: @users, fields: [:id, :name, :age], :encoding => 'SJIS'}
14
+ format.csv { render csv: @users, fields: [:id, :name, :age, :"groups.first.name"], encoding: 'SJIS' }
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,4 @@
1
+ class Group < ActiveRecord::Base
2
+ has_many :memberships
3
+ has_many :users, through: :memberships
4
+ end
@@ -0,0 +1,4 @@
1
+ class Membership < ActiveRecord::Base
2
+ belongs_to :user
3
+ belongs_to :group
4
+ end
@@ -1,4 +1,7 @@
1
1
  class User < ActiveRecord::Base
2
+ has_many :memberships
3
+ has_many :groups, through: :memberships
4
+
2
5
  def updated_at_as_csv
3
6
  self.updated_at.strftime("%F %H:%M")
4
7
  end
@@ -27,7 +27,7 @@ module Dummy
27
27
 
28
28
  # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
29
29
  # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
30
- # config.i18n.default_locale = :de
30
+ config.i18n.default_locale = :ja
31
31
 
32
32
  # Configure the default encoding used in templates for Ruby 1.9.
33
33
  config.encoding = "utf-8"
@@ -1,7 +1,12 @@
1
1
  ja:
2
2
  activerecord:
3
3
  attributes:
4
+ group: &groupmodel
5
+ name: グループ名
4
6
  user:
5
7
  id: ID
6
8
  name: 名前
7
9
  age: 年齢
10
+ groups:
11
+ first:
12
+ <<: *groupmodel
Binary file
@@ -0,0 +1,13 @@
1
+ class CreateGroups < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :groups do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :groups
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ class CreateMemberships < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :memberships do |t|
4
+ t.references :user
5
+ t.references :group
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :memberships
13
+ end
14
+ end
@@ -11,7 +11,20 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20120323112247) do
14
+ ActiveRecord::Schema.define(:version => 20120328072740) do
15
+
16
+ create_table "groups", :force => true do |t|
17
+ t.string "name"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+
22
+ create_table "memberships", :force => true do |t|
23
+ t.integer "user_id"
24
+ t.integer "group_id"
25
+ t.datetime "created_at"
26
+ t.datetime "updated_at"
27
+ end
15
28
 
16
29
  create_table "users", :force => true do |t|
17
30
  t.string "name"
Binary file