Rails + Nokogiri + Vue.jsでスクレイピング & SPAを作った
Rails + Nokogiri + Vue.jsを使ってシングルページアプリケーションを作りました。
史上5頭目の三冠牝馬アーモンドアイの競走成績表を作成してチェックできるアプリケーションです。
ネット競馬.comをスクレイピングしたデータをもとにRailsのモデルオブジェクトを作成し、非遷移で各データを表示します。
実用性、皆無!でも楽しかったからいいじゃない。
前回作ったはてなブログ風アプリケーションでは見た目部分をほぼBootstrapで実装しましたが、今回はCSSをしっかり書きました。
JavaScript, Vue.js, スクレイピング, CSSと初めて挑む分野が多く必死でしたがその分学べたことも多かったので、ページを分けてまとめました。
※このアプリケーションで取得しているデータは、競馬.comに登録することなく閲覧できるものに限られています
個々の記事へのリンク
axios.POSTした配列オブジェクトをRailsのモデルオブジェクトとして保存する
Railsの処理が失敗した時に失敗JSONを返すことでVue.jsの処理を分岐させる
全体の設計
はじめは「戦績一覧のレース名をクリックしたときに非遷移でレース結果を表示できたら面白いしJSの勉強になるぞ!」という思いつきで始めました。
モデル
- 開催日、馬場状態、レース名などのカラムを持つRaceモデル
- 着順、馬名、騎手、その他結果データのカラムを持つRecordモデル
の2つのモデルを作成。
コントローラ
・ Keiba_Dbコントローラ
・index 処理はなし。メインとなるページ
・ Api::KeibaDbコントローラ
・index すべてのRaceオブジェクトを返す
・destroy Raceオブジェクト(と関連付いている全てのRecordオブジェクト)を削除する
・create 選択したレースに紐づく全てのRecordオブジェクトを返す
・show アーモンドアイのnameカラムに紐づく全てのRecordオブジェクトを返す
・ Api::GetRaceRecordsコントローラ
・new params[:レース名]を元にスクレイピングして一つのRaceオブジェクトと複数Recordオブジェクトをnewして返す
・create Vueから送られてきたデータを元に一つのRaceオブジェクトと複数Recordオブジェクトを保存する
Railsのモデルオブジェクトとしてデータを作成&保存する部分は後から実装したため、コントローラの構成が非常に分かりづらくなってしまったのが反省点です。命名もマズい。
上から
- Homeコントローラ
・index - Api::Homeコントローラ
・race_index
・destroy
・records_index
・race_show - Api::Race_Recordsコントローラ
・new
・create
とかにすると分かりやすいかなと今考えましたが、この部分はRailsの思想というかMVCモデルにおけるコントローラの役割について調べ直してから着手することにします。
画面上の動き
データを見る
画面上にテーブルを2つ配置し、ページがロードされた状態ではRecordsにはアーモンドアイの成績のみをApi::KeibaDb#show
から表示しておき、レース名をクリックすると右のテーブルにそのレースに紐づく全てのRecordをApi::KeibaDb#create
から取得して表示します。
データを作る
データ追加ボタンを押すとモーダルが開きます。
レース名を入力してGETボタンを押すとApi::GetRaceRecords#new
にレース名が送られます。
newアクション内の処理は以下の通り。
ネット競馬.comのアーモンドアイ戦績一覧ページで、一致するレース名の href属性からレース詳細ページのURLをパースして取得。
↓
そのページの中で、
・レース名や開催日などをパースしてRaceオブジェクトをnew
・tableタグ内の各項目をパースして取得し、Recordオブジェクトの配列をnew
をして、それぞれをJSONで返します。
Vue.js側では
axiosでJSONをGETして、それぞれのデータをraceConfirmation
とrecordsConfirmation
に格納。
テーブルの各欄に並べたinputにv-modelで上記2つのデータを表示してデータの確認という形でモーダル内で提示します。
内容を確認してCREATEボタンを押すと、raceConfirmation
とrecordsConfirmation
の中身をaxiosがRailsのApi::GetRaceRecords#create
にPOSTし、Railsがそのデータを保存します。
間にユーザーによるデータ確認が入るのでApi::GetRaceRecordsコントローラでnewしたデータをそのまま保存するわけではない、という所がポイントです。
データの削除は単純で、選択したレースのIDがApi::KeibaDb#destroy
に送られて削除されるだけです。ただ削除後に更新されたレース一覧を非遷移で更新させる部分で少し詰まりました。
作業日程
7日間(だいたい80時間)
日曜日にジャパンカップを見てうおー!と思ってからそのうおー!を一週間保ち続けたまま完成まで突っ走りました。突っ走れたけど初めにもう少し細部まで仕様と設計を固めてから作ればよかった。
今回はあとでブログにまとめやすいように、こんな感じでブランチ名とコミットメッセージと共に作業工程を管理しました。
これはとても役立ちました。こういう管理のやり方についてももっと知りたくなった。まず企業に入ろう。
感想
・今回はJavaScript, Vue.js, Nokogiri, CSSと初めて触れるもの多かった。
基礎を学ぶ→実際に動くものを作る→ブログにまとめる→基礎をやった時に不明瞭だった所や応用知識を使って機能改善&リファクタリング→再びブログにまとめる
このサイクルでやってみたら非常に多く吸収することができた。
・「2つ目の言語を学ぶ時に、その言語自体を学ぶのと並行して"なるべく速く新しい技術を身につける方法"を確立できると幸せになれそうだな」と思っていたけど、今回そういう型(フレームワークだ!)がある程度固まったのでとても良かった。いろんなノウハウを身につけてもっと改良したい。
・スピード感は大事だけど、もう少し細部まで仕様と設計を考えてから作り始めたほうがいいかも。CSSも何も考えずに書くとゴッチャゴチャになるのでおおよそのHTMLの階層イメージとか考えておく
・ボタンのデザインとかはコピペで利用できるように公開されてるものが多々あるので、あまり深入りしすぎない。ただコピペしたものを改変できるように基礎知識は抑えておく。box-sizingなどの配置系とか。
・RailsとVue.jsのような組み合わせで開発するとき、それぞれに担当させる領域をどう線引きするかを勉強する。
・プログラミングはめちゃくちゃ楽しいので朝起きて飯食わずに夜までコード書くことも出来るけど、できればご飯はちゃんと食べる。睡眠は削らない。
・アーモンドアイはきっとめちゃくちゃ強い