やりたいこと
CSVなどのスプレッドシートから一気に読み込みたい。
(新規にシステムを作ったりするときにありがち)
前提
- Rails 4.2.5(4.x系) SQLiteを使用
- すでに登録対象のモデルが存在する。
登録対象のモデルに関しては、
objectという名前で
- name:string
- status:integer
- content:text
を持つと仮定する。
実装
ここを参照にした。ほぼこれに近いけど少し違うって感じ
- ビューに、ファイルを指定してアップロードする処理を呼び出す機能を実装
- コントローラに、ファイルの受け取りとリダイレクト処理を実装
- モデルに、内容に基づいた保存処理を実装
- ルーティングの設定
ビューの実装
アップロード箇所を実装したい表示させたいビューに、こんな感じの実装を行います。
実装箇所
<%= form_tag({controller: "objects", action: "import", method: "post"}, {multipart: true}) do %>
<%= file_field_tag :file %>
<%= submit_tag "オブジェクトを一括インポート" %>
<% end %>
コントローラの実装
コントローラは元々ビューやモデルに対する処理を呼び出したりする部分なので、ここではモデルに実装するDBアクセス処理の呼び出しと、リダイレクト処理を実装する。
さっきのビューでは、objectsのコントローラ、にimportという操作をpostメソッドでアクセスする。という意味合いになる。
app/controllers/objects_controller.rb
def import
Object.import(params[:file])
redirect_to "/object"
end
ここでは、読み込みファイルを引数として、モデルに実装したimportメソッドを呼び出し処理を行った上で、 /object の一覧ページにリダイレクトするという意味合いになる。
モデルの実装
モデルでは、対象のファイルを読み込み1件1件バリデーションして登録する処理を実施している。
関係ある箇所だけ抜粋。
例によってパラメータの精査も忘れず実施。
app/models/object.rb
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
obj = new
obj.attributes = row.to_hash.slice(*updatable_attributes)
obj.save!
end
end
def self.updatable_attributes
["name","status","content"]
end
ルーティングの修正
関係のあるところだけ抜粋
routes.rb
#objects に限り、post で import 処理を許可する
resources 'objects', only: :index do
collection { post :import }
end