2
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

railsでのcsv形式ファイルの出力、入力

Posted at

#CSVファイルとは
CSVファイルとはモデルのインスタンスの中身を外部へ出力したり、外部から入力するのに必要。具体的にいうと、出力は他のソフトウェアに出力するために使い、入力は他のソフトウェアからの大量データの一括などに使われる。

#####準備

config/application.rb
require 'csv'
#アプリ全体でcsvが使えるようにライブラリを取り入れる

#インスタンスの中身をCSV出力する方法
今回の例ではtaskモデルの全インスタンスの中身をCSVファイルで出力する

models/task.rb
#この関数ではcsv_attributesという配列変数を定義
  def self.csv_attributes
    ["name", "description", "created_at", "updated_at"]
  end

#CSV形式でインスタンスの中身を出力できるようにする
  def self.generate_csv
    #ここでcsv形式の配列csvを定義する、csv形式の配列に代入していくと列ベクトルができる?
    CSV.generate(headers: true) do |csv|
      #まずこのcsvに上記で定義したcsv_attributesを1行目として代入
      csv << csv_attributes
      all.each do |task| #taskを一つ一つ取り出して
        #csvの次に行にtaskの値を代入していく
        csv << csv_attributes.map{ |attr| task.send(attr) }
      end
    end
  end


定義したgenerate_csvを読み出すためにcontrollerに記述する

tasks_controller.rb
  def index #名前付きURLは/tasks
    .
    .
    .

    respond_to do |format| #この意味はURLのformatによって、新たに変更を加えるよという意味
      format.html #format.htmlの場合は、つまりURLが/tasksの時はという意味。format.htmlの後に処理が書かれていないため何もせず画面遷移する
      format.csv { send_data @tasks.generate_csv, filename: "tasks-#{Time.zone.now.strftime('%Y%m%d%S')}.csv" }
    #format.csvの場合は、つまり/task.csvになっている場合はという意味。その場合は後述の処理をする。ここではsend dataをしているので、データをブラウザからダウンロードされるようにしている
    end
  end


では/task.csvでアクセスするにはどうしたらいいのか。以下のようなリンクならアクセス可能

= link_to 'エクスポート', tasks_path(format: :csv), class: 'btn btn-primary mb-5'

#CSVデータを入力してデータ保存する方法
モデルファイルの中で受け取った値をデータとして保存する関数を定義する

models/task.rb
  def self.import(file)
    CSV.foreach(file.path, headers: true) do |row| #受け取ったCSVファイルを行ごとに取り出す、その時1行目headerには項目が書いてあるので、1行目は無視する
      task = new #Task.newと同価
      task.attributes = row.to_hash.slice(*csv_attributes) #taskの属性に順番にデータを格納していく。詳しくは調べてください
      task.save!
    end
  end


controllerの中で入力保存してリダイレクトするためのアクションを作る

tasks_controller.rb
  def import 
    current_user.tasks.import(params[:file])  #現在のuserのtaskにimportを発動させる
    redirect_to tasks_url, notice: "タスクを追加しました"
  end

ちなみにimportの読み出し方がcurrent_user.tasks.importの理解が意外と難しいのでメモ。モデルファイルの中でself.メソッド名で定義したメソッドはクラスメソッドとなるため、インスタンスではなくても使用できる。

現在taskモデルはuserモデルに従属しているのcurrent_user.tasksとすることで、今のユーザーのタスクモデル(クラス)のメソッドとして使用している。参考文献はRailsのmodelクラスのselfが曖昧だったので


ルーティング設定

routes.rb
  resources :tasks do
    post :import, on: :collection 
  end

c写真など大きなデータはURLにidとして挟み込めないので、collecionを使用することで、URLの引数として受け取れるようになる


入力画面設定

= form_tag import_tasks_path, multipart: true, class: 'mb-5' do
  = file_field_tag :file
  = submit_tag "インポート", class: 'btn btn-primary'

この入力でファイルを追加する時は拡張子が.csvになっていることを確認してからやりましょう。

2
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?