CSV形式のファイルのインポート/エクスポートについて
CSV形式とは?
1単語ずつカンマで区切られていて、1行ずつ情報が並んでいます。また、テキストデータとは文字のみのデータのことを指し、ワードやエクセルのように画像が入っていたり、文字サイズや色の装飾などがされていないプレーンな文字データのことを言います。通常のテキストデータの拡張子は「.txt」ですがCSVの場合は「.csv」となります。
# CSV形式の例 氏名,年代,性別,住所 山田 花子,30代,女性,東京都豊島区 田中 太郎,50代,男性,和歌山県有田郡
CSV
は各ソフトウェアが共通で対応している形式のため、異なるソフトウェア間で簡単にデータの移行が可能になっています。
csv形式のデータを扱うには、csvライブラリが必要です。
そのため、ライブラリを取り込んで、使えるように設定が必要です。
require 'csv' ~省略~
読み込み
# CSVライブラリを読み込む require "csv" csv_text = <<~CSV_TEXT Ruby,1995 Rust,2010 CSV_TEXT IO.write "sample.csv", csv_text # ファイルから一行ずつ CSV.foreach("sample.csv") do |row| p row end # => ["Ruby", "1995"] # ["Rust", "2010"] # ファイルから一度に p CSV.read("sample.csv") # => [["Ruby", "1995"], ["Rust", "2010"]] # 文字列から一行ずつ CSV.parse(csv_text) do |row| p row end # => ["Ruby", "1995"] # ["Rust", "2010"] # 文字列から一度に p CSV.parse(csv_text) # => [["Ruby", "1995"], ["Rust", "2010"]]
書き込み
# CSVライブラリを読み込む require 'csv' # ファイルへ書き込み CSV.open("path/to/file.csv", "wb") do |csv| csv << ["row", "of", "CSV", "data"] csv << ["another", "row"] # ... end # 文字列へ書き込み csv_string = CSV.generate do |csv| csv << ["row", "of", "CSV", "data"] csv << ["another", "row"] # ... end
1行変換
# CSVライブラリを読み込む require 'csv' csv_string = ["CSV", "data"].to_csv # => "CSV,data" csv_array = "CSV,String".parse_csv # => ["CSV", "String"]
現場Rails p312[csv出力する(エクスポート)]
app/models/task.rb
#タスクデータをCSVファイルとして出力する方法 class Task < ApplicationRecord # どの属性をどの順番で出力するかを定義してcsv_attributesメソッドで要素に属性名の文字列を持つ配列を作成します。 def.csv_attributes ["name", "description", "created_at", "updated_at"] end # CSV形式でインスタンスの中身を出力できるようにします。 def self.generate_csv # CSV.geterateでCSVデータの文字列を生成する CSV.generate(headers: true) do |csv| # headers: trueはデータベースの一番上の行(ヘッダー)をCSVのレコードのタイトルをとして指定します。 # csvに上記で定義したcsv_attributesを一行目として代入します。 csv << csv_attributes all.each do |task| # 省略前は、Task.all.each do |task| # Task.allでタスクを全件取得。その後、eachでtaskを一つ一つ取り出してtaskの値を代入していきます。 csv << csv_attributes.map{ |attr| task.send(attr) } # mapはcsv_attributesの配列の中身全てに対して処理を行います。 # この時、|attr|には["name", "description", "created_at", "updated_at"]が順番に入って処理に渡されます。 # task.sendは引数に指定したメソッドを文字列で返します。 # 文字列として返った属性名の中身をCSVに追加します。 end end end private ~省略~ end
<<
は配列の末尾に要素を追加するメソッド
Array#<< (Ruby 3.0.0 リファレンスマニュアル)
map() メソッド
は、与えられた関数を配列のすべての要素に対して呼び出し、指定した処理の結果を要素にした新しい配列を生成します。
# 配列の要素をすべて 3 倍にする→ その結果を新しい配列として生成する。 # 配列pの要素を順番に変数|n|に取り出してきて、そのnを使って、{ブロック内の後ろの処理を行う}。 # n * 3をした結果を新たな要素として配列を作成する。 p [1, 2, 3].map {|n| n * 3 } # => [3, 6, 9]
Array#collect (Ruby 3.0.0 リファレンスマニュアル)
sendメソッド
は、引数として渡されたメソッド(文字列、シンボル、変数として渡された)を実行し、その実行結果を返します。つまり、レシーバの持っているメソッドを呼び出してくれるメソッドです。 ブロック付きで呼ばれたときはブロックもそのまま引き渡します。
class User def name puts "taro" end end user = User.new #定義したメソッドを呼び出す user.name # => taro # sendを使った書き方 user.send(:name) # => taro user.send("name") # => taro
Object#send (Ruby 3.0.0 リファレンスマニュアル)
CSV.generateメソッド
は、与えられた文字列をラップして CSV のオブジェクトとしてブロックに渡します。ブロック内で CSV オブジェクトに行を追加することができます。ブロックを評価した結果は文字列を返します。
generate(str = "CSVに変換したい文字列", options = Hash.new) {|csv| ... } -> String
CSV.generate (Ruby 3.0.0 リファレンスマニュアル)
app/controller/tasks_controller.rb
# コントローラに異なるフォーマットでの出力機能を追加する def index ~ 略 ~ respond_to do |format| # formatがHTMLとしてアクセスされた場合 format.html # formatがCSVでアクセスされた場合 # send_dataメソッドを使って、レスポンスを送り出します。 # モデルで定義したgererate_csvメソッドを使って、タスクデータをCSV形式にしたものをレスポンスとしています。 format.csv { send_data @tasks.generate_csv, filename: "sample.csv"} end end
参照
【Ruby】よく使う、CSVライブラリを使ったCSV操作 - Qiita
Array#<< (Ruby 3.0.0 リファレンスマニュアル)
Array#collect (Ruby 3.0.0 リファレンスマニュアル)
Object#send (Ruby 3.0.0 リファレンスマニュアル)
【Ruby on Rails】sendメソッドのいろんな書き方 - Qiita