LoginSignup
23
29

More than 3 years have passed since last update.

【Rails】CSVファイルからデータをインポート

Posted at

簡単なTODOアプリに、CSVファイルからタスクを追加する機能を実装します。
手順は以下の記事で説明されているものとほとんど同じです。めちゃくちゃ参考になりました。
【Ruby on Rails】CSVインポート

実装

タスク追加、編集、削除機能、ログイン機能などを持つTODOアプリにCSVアップロード機能を実装して行きます。
Ruby on Railsで簡単なアプリを作成
【Rails】ログイン機能を実装する

rubyの標準ライブラリcsvを追加

/config/application.rb
require 'csv'

rooというgemを追加

csvファイルを読み込むためのgemrooを追加します。

Gemfile
gem 'roo'
terminal
$ bundle install

タスク一覧画面にcsvアップロード用のフィールドを追加

/app/views/tasks/_logged_in.html.erb
<%= form_tag import_tasks_path, multipart: true do %>
  <%= file_field_tag :file %>
  <%= submit_tag "インポート" %>
<% end %>

コントローラーにアクションを追加

Task.import(params[:file])で使われているimportメソッドは後ほど定義します。

/app/controllers/tasks.controller.rb
def import
  Task.import(params[:file])
  redirect_to root_url
end

ルーティングを設定

collection {post :import}と書き込むことで、resources :tasksで作成されるルーティング以外の、tasksコントローラーのアクションへのルーティングを追加することができます。

/config/route.rb
resources :tasks do
  collection {post :import}
end
terminal
$ rails routes
.
.
import_tasks POST   /tasks/import(.:format)   tasks#import
.
.

import_tasksという名前付きルートが追加されました。

モデルにCSV読み込み、登録処理を実装

/app/models/task.rb
#importメソッド
def self.import(file)
  CSV.foreach(file.path, headers: true) do |row|
    # IDが見つかれば、レコードを呼び出し、見つかれなければ、新しく作成
    task = find_by(id: row["id"]) || new
    # CSVからデータを取得し、設定する
    task.attributes = row.to_hash.slice(*updatable_attributes)
    task.save
  end
end

# 更新を許可するカラムを定義
def self.updatable_attributes
  ["title", "user_id"]
end

動作確認

以下のようなファイルを用意します。

taskForTodoApp.csv
title,user_id
パンを買う,2
筋トレ,2
メルカリの発送,8
ティッシュを交換する,2

実行結果
 2019-11-28 18.43.08.png

ハマったポイント

・CSVファイル内にuser_idを記載しておらず、データベースへの登録時にエラーが発生していたところで少しハマりました。

TODO

・TSVファイルも取り込めるようにする

参考

【Ruby on Rails】CSVインポート

23
29
5

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
23
29