我得到了一系列我希望转换为CSV的ActiveRecord模型。我尝试过研究像FasterCSV这样的宝石,但它们似乎只使用字符串和数组,而不是ActiveRecord模型。
简而言之,我想转换:
user1 = User.first
user2 = User.last
a = [user1, user2]
至:
id,username,bio,email
1,user1,user 1 bio,user1 email
1,user2,user 2 bio,user2 email
有一个简单的Rails方法来做到这一点?
以下内容将所有用户的属性写入文件:
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
@ rudolph9的答案非常棒。我只想给那些需要定期完成这项任务的人留一张纸条:将它作为一个rake任务是一个好主意!
LIB /任务/ 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
如果您需要快速而肮脏的东西,而不仅仅是为非技术用户抓取一些数据,那么您可以将其粘贴到控制台中:
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的装饰器,更准确地说是确保你的字段/属性的顺序。
这可能不是原来的问题,但解决了问题。如果您计划将所有或部分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关系,不适用于数组
使用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)
还有一个类似的答案,但这就是我通常做的事情。
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
方法将可用于Model及其Relation。例如。
User.where(role: :customer).to_csv
# => gets the csv string of user whose role is :customer
也可以使用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。那个版本还不知道separator
和once
。因此,您可能需要从网站下载最新的二进制文件:https://sqlite.org/download.html在本地安装它,并使用本地安装的完整路径:
~/.local/bin/sqlite3 -init lib/tasks/export-submissions.sql db/development.sqlite3 .exit