web-dev-qa-db-ja.com

ActiveRecordモデルの配列をCSVに変換する方法は?

CSVに変換したいActiveRecordモデルの配列を取得しました。 FasterCSVのようなgemを調べてみましたが、ActiveRecordモデルではなく、文字列と配列で動作するようです。

要するに、私は変換したい:

user1 = User.first
user2 = User.last
a = [user1, user2]

TO:

   id,username,bio,email
    1,user1,user 1 bio,user1 email
    1,user2,user 2 bio,user2 email

簡単なRailsこれを行う方法はありますか?

41
Henley Chiu

以下は、すべてのユーザーの属性をファイルに書き込みます。

CSV.open("path/to/file.csv", "wb") do |csv|
  csv << User.attribute_names
  User.find_each do |user|
    csv << user.attributes.values
  end
end

同様に、CSV文字列を作成できます。

csv_string = CSV.generate do |csv|
  csv << User.attribute_names
  User.find_each do |user|
    csv << user.attributes.values
  end
end
97
rudolph9

@ rudolph9の答えは本当に素晴らしいです。定期的にこのタスクを実行する必要がある人のためにメモを残したいだけです。レーキタスクとして作成することは良い考えです。

lib/tasks/users_to_csv.rake

# usage:
# rake csv:users:all => export all users to ./user.csv
# rake csv:users:range start=1757 offset=1957 => export users whose id are between 1757 and 1957
# rake csv:users:last number=3   => export last 3 users
require 'csv' # according to your settings, you may or may not need this line

namespace :csv do
  namespace :users do
    desc "export all users to a csv file"
    task :all => :environment do
      export_to_csv User.all
    end

    desc "export users whose id are within a range to a csv file"
    task :range => :environment do |task, args|
      export_to_csv User.where("id >= ? and id < ?", ENV['start'], ENV['offset'])
    end

    desc "export last #number users to a csv file"
    task :last => :environment do |task, arg|
      export_to_csv User.last(ENV['number'].to_i)
    end

    def export_to_csv(users)
      CSV.open("./user.csv", "wb") do |csv|
        csv << User.attribute_names
        users.each do |user|
          csv << user.attributes.values
        end
      end
    end
  end
end
11
Brian

これは元の質問から外れているかもしれませんが、問題を解決します。 Active Recordモデルのすべてまたは一部をcsvに変換できるようにする場合は、ActiveRecordに関する懸念事項を使用できます。以下に例を示します

_module Csvable
  extend ActiveSupport::Concern 

  class_methods do
    def to_csv(*attributes)
      CSV.generate(headers: true) do |csv| 
        csv << attributes 

        all.each do |record| 
          csv << attributes.map { |attr| record.send(attr) }
        end 
      end
    end
  end
end
_

指定された属性はCSVのヘッダーとして使用され、この属性は含まれるクラスのメソッド名に対応することが期待されます。次に、任意のActiveRecordクラス、この場合はUserクラスにそれを含めることができます

_class User 
  include Csvable 

end
_

使用法

User.where(id: [1, 2, 4]).to_csv(:id, :name, :age)

注:これはActiveRecord関係でのみ機能し、配列では機能しません

2
theterminalguy

本番ではなく、技術に詳しくないユーザーのためにデータを取得するだけでなく、迅速で汚れたものが必要な場合は、これをコンソールに貼り付けることができます。

_require 'csv'
class ActiveRecord::Relation
  def to_csv
    ::CSV.generate do |csv|
      csv << self.model.attribute_names
      self.each do |record|
        csv << record.attributes.values
      end
    end
  end
end
_

それから:User.select(:id,:name).all.to_csv

本番環境に行く場合は、おそらくこれをActiveRecord :: Relationのデコレーターに変換し、より正確にフィールド/属性の順序を確認します。

2

さらに別の同様の答えですが、ここに私が通常行うことを示します。

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

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

既存のモジュールをハッキングする代わりに、通常、このコードをすべてのモデルの基本クラスであるApplicationRecordクラスに配置します(通常)。

さらに詳しく説明する必要がある場合は、to_csvメソッドに名前付きパラメーターを追加し、このクラスでこれらの機能を可能な限り処理します。

このようにして、to_csvメソッドはモデルとそのリレーションの両方で利用可能になります。例えば。

User.where(role: :customer).to_csv
# => gets the csv string of user whose role is :customer
1
Yuki Inoue

Julia_builder を使用すると、csvエクスポートを非常に簡単に構成できます。

class UserCsv < Julia::Builder
  # specify column's header and value
  column 'Birthday', :dob
  # header equals 'Birthday' and the value will be on `user.dbo`

  # when header and value are the same, no need to duplicate it.
  column :name
  # header equals 'name', value will be `user.name`

  # when you need to do some extra work on the value you can pass a proc.
  column 'Full name', -> { "#{ name.capitalize } #{ last_name.capitalize }" }

  # or you can pass a block
  column 'Type' do |user|
    user.class.name
  end
end

その後

users = User.all
UserCsv.build(users)
1

これには、SQLエンジンも利用できます。例えば。 sqlite3の場合:

cat << EOF > lib/tasks/export-submissions.sql
.mode      csv
.separator ',' "\n"
.header    on


.once "submissions.csv"

select
  *
from submissions
;
EOF

sqlite3 -init lib/tasks/export-submissions.sql db/development.sqlite3 .exit

CentOS 7を使用している場合-2013年にリリースされたsqliteに同梱されています。そのバージョンはseparatoronceをまだ知りませんでした。そのため、Webサイトから最新のバイナリをダウンロードする必要がある場合があります。 https://sqlite.org/download.html それをローカルにインストールし、ローカルインストールへのフルパスを使用します。

~/.local/bin/sqlite3 -init lib/tasks/export-submissions.sql db/development.sqlite3 .exit
0
Adobe