【Rails】ネストされた、子要素にCSVインポート機能を実装してみる。
今回は、CSVファイルのインポート(一括入力)処理を作っていきます。
スクールのカリキュラムに載っていない内容なので
書く前からそわそわしております・・・。
間違っていたら、優しく教えていただけるとありがたいです。
おぢさんのメンタルはやわらか戦車よりやわらかいので・・・。
と言う事で、最終的な完成形の流れはこんな感じです。
- 1.最初は、親のcalendaer(入荷日)を決めます。
- 2.親のcalendaer(入荷日)に関連する入荷物をCSVファイルから一括入力します。
すると、入荷物を一括で見る事ができます。
目次
- 目次
- 1.前提条件
- 2.課題は山積み
- 3.CSVファイルを読み込む準備
- 4.importアクションを設定(ルーティングの記述変更 )
- 5.ビューを実装(フォームを作成)
- 6.CSVインポート作業を実装
- 7.残る課題
- 8.参考にさせていただいたサイト様
1.前提条件
1-1.モデル
親(calender)
わかりやすくする為、バリデーションは省いています。
マイグレーションは割愛します。
ポイントは
- アソシエーションを記述して、stockモデルとの親子関係を定義
- 「dependent: :destroy」を記述して、親を削除すると関連する子のデータも消す
子(stock)
こちらのマイグレーションは今はここまで。
後で修正をかけるのですが、現時点では割愛します。
ポイントは
- アソシエーションを記述して、stockモデルとの親子関係を定義
1-2.ルーティング
ネストは、ある記述の中に別の記述をして、親子関係を示す方法です。
「入れ子構造」とも呼ばれますね。
と言う事で、calenderコントローラーのルーティングの中に、stockコントローラーのルーティングを記述しています。
1-3.コントローラー
こちらは、実装の主役であるstockコントローラーだけです。
今のところ、定義するのはindexだけですね。
親(calender)のデータと
付随する子(stock)のデータを全て出力します。
1-4.ビュー
こちらも、今回の主役stock/index.html.erbだけ。
大事なところだけ抜き出しています。
登録したデータをエクセルの様な感じで表示してくれます。
csvのファイルデータは他にもっとあるのですが、
画面に表示するのは7項目だけって事ですね。
1-5.テーブル(表)タグの説明
<table>はテーブル(表)を作成するタグですね。
テーブル(表)の基本的な構造としては
<table>~</table>内に<tr>〜</tr>で表の横一行を定義して
さらにその中に<th>〜</th>や<td>〜</td>でセルを定義したりします。
テーブル(表)の各セルには
見出しを定義するヘッダセル(<th>〜</th>)と、
データを定義するデータセル(<td>〜</td>)があります。
ヘッダセル内のテキストは、一般的な画面では太字で中央に表示されるみたいです。
後は、スタイルシートで装飾してあげます。
2.課題は山積み
今回の実装をするにあたり、解決しないといけない事が結構ありまして
先ずはそちらを書き出していきます。
大きくはこの3点です。
あ〜でもない、こ〜でもないと苦悩の日々が始まります。
3.CSVファイルを読み込む準備
先ずはCSVファイルなどを読み込む事ができるGem「Roo」を読み込みます。
3-1.Gem「roo」
「Roo」は、スプレッドシートタイプの読み取りアクセスができるライブラリで
今回はCSVを読み取るために使わせていただきます。
他にも
などが処理できる様です。すごい便利!
ライブラリをGemfileに追加し、bundle installしちゃいましょう。
3-2.CSVファイルを確認
今回使うCSVファイルを用意します。
123456,テスト,テスト,〜省略〜, ,
123456,テスト,テスト,〜省略〜, ,
123456,テスト,テスト,〜省略〜, ,
めっちゃ項目が多いので省略しまくりました。
ポイントとしては、ヘッダーが日本語表記だと言う事ですね。
3-3.マイグレーションを記述
CSVファイルの内容に合わせてマイグレーショを記述していきます。
4.importアクションを設定(ルーティングの記述変更 )
config/routes.rbに下の様に記述を追加します。
これで、
この様に、importアクションが追加されました。
5.ビューを実装(フォームを作成)
5-1.コントローラーを記述追加
今回は、「new」画面でフォームを作成したかったので
「newアクション」を先に記述追加します。
ポイントは親のidを忘れずに持ってくるぐらいですかね。
5-2.ビュー作成。
そして、ビューですがこんな感じです。
ポイントは3つ。
- 「form_with」を使うといろいろ省略できて便利。
- 「method: :get」をつけない。
- 「accept: '.csv'」 を記述する。
順に説明しますと
補足説明1.form_with」を使うといろいろ省略できて便利。
csvインポートを実装したくて、Qiitaや各ブログを拝見していましたら
多くの方が
と、言う様な記述をされていたのですよね。
この「multipart(マルチパート)」は
画像やCSVなどのファイルを読み込む際に必要になってくる記述なのですが
form_withを使う場合は省略可能で、
form_with内にfile_fieldが存在すれば自動的にmultipartが適用されちゃうそうです!
便利な世の中になったもんだ・・・。
これは、Rails 5からだそうです。
カリキュラムでは何も知らずに使っていましたがバージョンアップってすごい!
補足説明2.「method: :get」をつけない。
getリクエスト(form_withにmethod: :getを指定する)にしてしまうと
パラメータがnilになっちゃうらしくでデフォルトのpostのままにします。
補足説明3.「accept: '.csv'」 を記述する。
「file_field」に「 accept: '.csv'」 を書くことで、
csvファイルだけが選択される様になります。
(ファイル選択時、csvファイル以外は非活性状態になってます)
6.CSVインポート作業を実装
も〜、ここで1週間ぐらい悩みました。
自分なりに出した結論は以下の様な感じです。先ずはコントローラーから
6-1.importアクションを記述
長くなりそうなので、インポートアクションのみ記述します。
ポイントは記述順に
- 親のデータを取得しておく
- importで送られるデータはcsvのファイルと親のidにしておく。
- ちゃんと登録できたか、確認のためにフラッシュも付けておく。
6-2.モデルに記述追加
こちらも長くなりそうなので所々省略します。
複雑な作業をコントローラーでさせる訳にはいかないので、モデルに記述します。
モジュールに書き出して呼び出すと言う方法もある様です。
ポイントは3つ
- ヘッダーが日本語問題対策
- CSV.foreachのオプションで指定しているもの
- 親のidを別途登録
順に説明していきます。
補足説明6-1.ヘッダーが日本語問題対策
ヘッダーが日本語なので、そのままだとattributesに入れる事ができない・・・
csvファイルをそのまま取り込むことはできました。
ただし、localhos上だけですが。
(試していないのですがheroku上でも大丈夫なのではないでしょうか。)
ただ、ここで楽をしてしまうと、成長止まるかなとも思いチャレンジです。
ヘッダーの項目名とテーブルのカラム名のハッシュを
「CSV_HEADER」として定義しておいて、
「transform_keys」でカラム名に一致するように入れ替えます。
これで、modelのattributesに対応します。
補足説明 6-2.各記述の説明
「CSVforeach」で一行ずつ解析していくのですが
headers: true:ヘッダーを読み飛ばしてくれます!
今回のCSVファイルにはIDの表記がないので
もし合った場合はそのレコードを呼び出し、ない場合は新しく作成。
CSV_HEADERを基にして、hashに変換する。
最後に、親のidを追加
ふ〜・・・。やっとできました!
7.残る課題
やっとこさ出来上がってはみたのですが
記述方法が悪いのかなんだか取り込みスピードが遅い気がするのですよね。
herokuだともっと遅い気がします。
この辺を勉強して、早く処理できる様になったらまたブログにします!
8.参考にさせていただいたサイト様
[Rails6]CSVインポート処理を作る|ota|note
どちらの方にも足向けて眠れません。
自分なりの解釈も入れてはいますがほぼ上記の方々の書かれているとおりです。
少しづつでも理解して行って、どなたかの助けになっていたらいいな〜。