初心者がRailsとVue.jsでポートフォリオを作成してみた

こんばんは
アロハな男、やすのりです！

私は、自身のポートフォリオとして『Vue.js』と『Rails』を使用した、SPAアプリを作成しました。

この記事ではポートフォリオの内容や、実際に様々な機能実装をする上で『工夫したこと・苦労したこと』や、Webアプリ開発を通しての感想等をお伝えしていきたいと思います！

#アプリ概要
一言で説明すると、**ハワイに特化した『じゃらん』や『一休.com』** です。

[![Image from Gyazo](https://i.gyazo.com/f746c7ba571c12f80f506d94f5f63675.gif)](https://gyazo.com/f746c7ba571c12f80f506d94f5f63675)

今のご時世では気軽に旅行することも難しいのですが、私自身や周りに旅行することが好きで、特にハワイが好きな方々がおり、実際に旅行した際の思い出やおすすめのお店等を共有し合うことがありました。

そこで、自身の思い出の場所やおすすめ店等を共有したいと思い、様々なサイトを探してみましたが、**『管理人のおすすめ店をランキング形式で紹介』**というものが多く、おすすめの場所が複数ある場合は、その分複数のサイトを共有しながら話し合うという様な形でした。

そういった経験から『もし、ハワイのお店やアクティビティ等がまとめられ、口コミ等でユーザーの評価がわかる様なサイトがあればお気に入りの場所もおすすめしやすくていいな』という想いから、このアプリを作成することにしました。

また、アプリ作成をする上で『説明がなくてもユーザーが使える見た目』であることや『ユーザーとしてアプリを使用する上で欲しい機能』を常に考え、**『ユーザーが使いやすいアプリ』**をコンセプトにアプリを作成しました。

下記ページにて公開中ですので、よろしければ実際に触ってみてください！
https://www.lets-enjoy-hawaii.com

#使用技術等
* **フロントエンド**
    * **Vue.js 2.6.12**
    * **Vue Router**
    * **axios**
    * **JavaScript**
    * **HTML / CSS**
    * ~~**Haml / SCSS**~~※Vue.jsの導入に伴い使用中止
    * ~~**jQuery**~~※Vue.jsの導入に伴い使用中止
* **バックエンド**
    * **Ruby 2.6.5**
    * **Rails 6.1.2.1**
* **テスト**
    * **Rspec**
    * **FactoryBot**
    * **faker**
    * **rubocop**
* **インフラ**
    * **AWS (VPC, EC2, S3, RDS, Route53)**
    * **https化**
    * **Nginx / Unicorn**
* **ソースコード管理**
    * **GitHub**

#機能一覧

* **ユーザー管理関連機能**(devise_token_auth / Vuex / axios)
    * 新規登録機能
    * ログイン・ログアウト機能
    * ユーザー情報更新機能(アイコン画像含む)
    * お試しユーザー機能
    * お試しユーザー情報変更制限機能
    * [入力フォームの入力不備表示機能](#入力フォームの入力不備表示機能)
        * ログイン・会員登録画面内
    * [会員登録済みメールアドレスお知らせ機能](#会員登録済みメールアドレスお知らせ機能)
    * お店等へのお気に入り・訪問記録登録機能
    * [登録済みのお気に入り・訪問記録へのメモ書き機能](#登録済みのお気に入り訪問記録へのメモ書き機能)

* **検索関連**(ransack / Vuex / axios)
    * キーワード検索機能
    * 各項目検索機能
    * [地図検索時、選択場所の表示変更機能](#地図検索時選択場所の表示変更機能)
    * [検索結果の並び替え機能](#検索結果の並び替え機能)

* **お店等の詳細表示関連**(Active Storage / Vuex / axios / Google Street View API)
    * お店等への口コミ投稿機能
    * [お店等への画像投稿機能(複数枚投稿可能)](#お店等への画像投稿機能複数枚投稿可能)
    * お店等のレーティング表示機能
    * [棒グラフ表示機能](#棒グラフ表示機能)
        * お店等への評価点の分布表示用
    * 投稿された口コミ・画像の一覧表示機能
    * 口コミの並び替え機能
    * お気に入り登録数表示機能
    * [Google APIを使用したお店等の画像取得機能](#google-apiを使用したお店等の画像取得機能)

* **その他**
    * トップページからのパンくずリスト表示機能(gretel)
    * バリデーション機能
    * ログイン前後等のリダイレクト機能

以降では、主要機能の詳細や工夫点等について紹介させていただきます！

# 入力フォームの入力不備表示機能
`機能詳細`
入力フォームの各項目に対して、モデルのバリデーション設定に反した入力がされるとエラーメッセージが表示され、入力欄の表示が変更されます。
※バリデーション設定に沿った入力がされた段階で、エラーメッセージや入力欄の表示が元に戻ります。

[![Image from Gyazo](https://i.gyazo.com/55f34d3207c5f4075e8aa01d5e6b36dc.gif)](https://gyazo.com/55f34d3207c5f4075e8aa01d5e6b36dc)

###工夫点
####①入力不備の場所を判断できる様にする
入力項目が複数あるため、エラーメッセージを表示しただけでは、どの入力欄で入力不備が起こっているのか判断がつけづらいと考え、入力欄自体の表示も変更することにより、どの入力欄で不備が発生しているのかがすぐ判断できる様にしました。

####②入力不備が解消されたかどうか一目でわかる配色にする
ページに使用している配色とは異なった色で入力不備の表示をすることにより、入力不備が解消されているかが一目でわかる様にしました。

# 会員登録済みメールアドレスお知らせ機能
`機能詳細`
会員登録時に入力されたメールアドレスが**既に登録済みか判定**し、登録済みであればエラーメッセージを表示させ、別のアドレスを入力するか、ログインを試すかを促す様にしています。

[![Image from Gyazo](https://i.gyazo.com/3de4c3ca1bf8afd17f6da9fe7495aec5.gif)](https://gyazo.com/3de4c3ca1bf8afd17f6da9fe7495aec5)

###懸念点
####ユーザー登録数が増えてきた場合の処理速度問題
メールアドレスの入力がされ入力欄からフォーカスが外れた際に、axiosを使用した非同期通信を行い、メールアドレス判定用メソッドへリクエストを飛ばします。
現在は登録数が少なくレスポンスも早いですが、登録数が膨大になった際は時間がかかってしまうことが考えられますので、判定中なことをアイコンで表示させる等の処理が必要そうです。

詳しいコード解説等は別記事にて紹介しています。
<a href="https://qiita.com/yasunori_aloha/items/9f060a39823c15c44913">RailsとVue.jsでメールアドレスが登録済みか判定する方法</a>

# 登録済みのお気に入り・訪問記録へのメモ書き機能
`機能詳細`
登録済みの**お気に入り**や**訪問履歴**に対して『〜が美味しかった！』や『次は〜動物をメインに見たい』等のコメントを、メモ書き感覚で保存することができます。

[![Image from Gyazo](https://i.gyazo.com/83be03f87514f0cc0da64a960a634ea5.gif)](https://gyazo.com/83be03f87514f0cc0da64a960a634ea5)

###工夫点
####保存ボタンを押すことにより、コメント保存がされる様に設定
最初は各お店等へコメントでのメモ書きをする際に、『保存ボタン』をクリックしなくても、入力欄のフォーカスが外れた段階で保存処理をかければ、ユーザーの手間が1つ減るのではないかと考えていました。
しかしその仕様にした場合、『入力したけど、元々残していたメモ書きの方がやっぱりいい』や『誤ってメモ書きを削除してしまった』等といった場合に対応できないと考えを改め、『保存ボタン』も一緒に実装しました。

# 地図検索時、選択場所の表示変更機能
`機能詳細`
トップページの『地図から探す欄』と『島名から探す欄』にて島名等をホバーすると、対応した地図上の島の表示が変更されます。

[![Image from Gyazo](https://i.gyazo.com/c1abb18b13350009d082c677346932f2.gif)](https://gyazo.com/c1abb18b13350009d082c677346932f2)

###工夫点
####①選択している島を視覚的にわかる様に設定
最初は地図上をホバーしても、マウスの表示が変わって地図を選択していることをお知らせしているだけでした。
しかし、地図上の表示も合わせて変更することによって、実際にユーザーが選択している箇所を把握することも容易になるのではないかと考え、地図上の表示変更機能を実装しました。

####②島名にどこの島が対応しているのかわかる様に設定
島名検索をする際に、**『オアフ島やハワイ島は聞いたことがあるけど、実際地図上ではどこになるんだろう』**という声をいただき、実際に島名選択時にどの島と対応しているのかを地図表示を変更することでわかる様に設定しました。
これによって、『今回はオアフ島へ旅行に行くから、その横の島も時間があれば観光をする予定を立てよう』等の新たな計画を立てることもできるのではないかと思っています。

# 検索結果の並び替え機能
`機能詳細`
並び替え欄にある**口コミランク順**等をクリックすることで、表示されているお店等の検索結果一覧の並び替えをすることができます。

[![Image from Gyazo](https://i.gyazo.com/dc0238454c0249ee3cd80bad9e971295.gif)](https://gyazo.com/dc0238454c0249ee3cd80bad9e971295)

###工夫点
####①初期状態の並び順をお気に入り数の多い順に設定
ユーザーが目的の場所を検索する際に**評価の高い場所を優先的に見ていく**と考え、口コミランク順かお気に入り数の多い順のどちらかを初期状態にしようと考えました。
その際に、**『口コミ投稿をするより、お気に入りボタンを押す方が簡単でユーザーが使用する割合が高い』**と考え、口コミ投稿に影響される『口コミランク順』ではなく、お気に入り数順を初期状態とすることにしました。

####②並び替えボタンに使用頻度が高そうなものを用意
ユーザーが実際に並び替えをしたい項目にどういったものがあるかと考えました。
その際に『口コミランク順』と『お気に入り数順』は①でも説明した様に、ユーザーは評価の高いところを知りたいのではないかと思い、追加しました。
そして更に**『口コミ数が多く、その場所に対しての感想が多い方が、よりその場所へのイメージがしやすい』**のではないかと考え、『口コミ数順ボタン』を実装しました。

# お店等への画像投稿機能(複数枚投稿可能)
`機能詳細`
お店等への口コミと一緒に、写真を投稿することもできます。
1回の投稿につき複数枚選択していただくことができ、現在どんな写真を選択しているのかをプレビューすることもできます。
そして、**写真削除ボタン**をクリックすることで、クリックした画像を選択画像から除外することができます。

[![Image from Gyazo](https://i.gyazo.com/b954bc9d10ed893303bf1f05ed5df273.gif)](https://gyazo.com/b954bc9d10ed893303bf1f05ed5df273)

###工夫点
####写真削除ボタンをホバーした際に、ホバーした**写真削除ボタン**の表示を変更する。
写真を複数枚プレビューさせるためにVue.js上で繰り返し処理を行い各要素を表示させているため、そのままmouseoverイベントを発火させてしまうと、**全ての写真削除ボタンの表示が変更されてしまう状態**になっていました。
なので、削除ボタンにref属性を付与して、繰り返し処理のindex番号を与え、その**ref属性とindex番号でホバーした要素を判断し表示を変更させる**ことができました。

# 棒グラフ表示機能
`機能詳細`
お店等へ投稿された口コミの評価点の分布を、棒グラフで表示させています。
また、口コミが投稿されるとパーセントも更新され、グラフの表示も変動します。

[![Image from Gyazo](https://i.gyazo.com/807ae3bb8440fc18a3f22e7d3434e479.png)](https://gyazo.com/807ae3bb8440fc18a3f22e7d3434e479)

###工夫点
####パーセント表記に小数点を使用しない
各評価点のパーセンテージを計算した際に、どうしても割り切れず小数点が発生してしまいましたが、表示上はすっきりさせている方が見た際にわかりやすいと考え、小数点以下は四捨五入し表示をさせています。

# Google APIを使用したお店等の画像取得機能
`機能詳細`
今のご時世ですので、実際に現地に行かなくても、お店の画像を取得し使用することができる**『Google Street View API』**を使用しました。

[![Image from Gyazo](https://i.gyazo.com/dc745cfd2a9421cd975d49ec9125247d.jpg)](https://gyazo.com/dc745cfd2a9421cd975d49ec9125247d)

###問題点
####①全ての場所は対応していない
画像自体はGoogle Streetにあれば取得することができますが、そもそもショッピングモールの中のお店等は表示されなかったりするので、画像が取得できずに掲載できないお店等も存在します。

####②データベースに保存するカラムが増える
『Google Street View API』を使用するために、該当場所の座標等の情報をデータベースに保存しなければならないため、1つのレコードに使用される容量が増えてしまう。

以上のことから、可能であれば少しずつでも実際に現地で撮影した写真等を入手する必要があると考えています。

##追加実装予定
GithubのIssuesに、実装内容と目的をまとめています。
https://github.com/Yasunori-aloha/lets-enjoy-hawaii/issues

#ポートフォリオ開発で苦労したこと
特に苦労したことは、フロント部分とバック部分との連携でした。

当初はRailsだけで開発しており、フロント部分もRailsのビューを使用し実装していました。
しかし、現在主流なのは『フロント部分はVue.jsやReact等のJavaScriptフレームワークを使用してバック部分と切り分けて実装されるアプリケーション』であることや『フロントとバック両方の知識・技術があれば、実務に入った際のフロントとバック両チームのコミュニケーションの架け橋になれるのではないか』と考え、フロントをVue.jsへ切り替えを決心しました。

しかし、1度完成させていたものを新たに『APIモード』として作り替えるために、

* APIモードでの必要情報の取り出し方
* ビューをVue componentsとして移行

等々を新たに学習し直して、実装する必要がありました。

参考文献も少なく、スクール等では学べない内容でしたので、自分自身の成長により繋がったのではないかと思います。


#ポートフォリオ開発を通しての得たもの
* 自走力
Railsだけでポートフォリオ完成させた段階では、どうやってVue.jsを連携させればいいのか全く知識がなかった状態からのスタートでしたので、導入の部分から実装部分に至るまで様々なエラー・不具合に遭遇してきました。
しかし、Udemyの教材等を活用し、基礎的な内容から実践的なものまで学習を続けたことで、学習開始からポートフォリオへの導入まで約1ヶ月でVue.jsを実装することができました。
そして、そのほとんど全てのタスクを自力で実装することができるまでになっていました。

* デバック力
ポートフォリオを作成する中で、様々なエラーに何度も遭遇してきました。
ですが、その度にbinding.pryやdebugger等のデバックツールを使用して、**『どこまで自身の想定内の動作をしているのか？』**を明確にし、エラーの原因を絞り込み特定し解決、というサイクルを何度も経験し乗り越えてきました。
今では、エラーに遭遇しても『今回はどういった理由でエラーが出てるのかな？』と、原因特定するこのサイクル自体を楽しんでいる自分がいました。

* とにかく楽しむこと
このポートフォリオを作成する中で、実装したい機能を実現するための方法を考えたり、考えたロジックをコードに落とし込んだり、エラーが発生した箇所はデバックをすることで原因を追及し解決する。
こういった開発の流れ全てを楽しみながら開発を続けることができました。
RailsだけでなくVue.jsも取り入れることで『フロント側ではこの情報が必要だからレスポンスで渡せる様にしよう』と考えたり、『バック側の処理でこの値が必要だからリクエストで送ってあげよう』と考えながら実装していくことでお互いの知識・技術も向上され、更にお互いのことを考えるための思考も養われたのではないかと思います。

#最後に
ポートフォリオ開発を通して1番はじめに思い返されるのが『楽しくすることができた』ことです。
特に新たに実装したい機能が浮かんできて、その機能を実装するための方法を考えて、様々な教材で学習し実際に機能を実装できた時はとても大きな感動と達成感があったことを覚えています。

開発を始めたばかりの頃は、わからないことも多くエラーや実装方法で苦労することも多々ありましたが、実際に当初自身で実装したいと思っていた機能が実装することができて本当に良かったと思います。

まだまだ、開発過程で実装したいと思った機能がありますので、これからもアップデートを続けて、よりユーザーの使いやすいアプリケーションにできる様、そして自身の知識・技術が向上できる様に学習を続けていきたいと思います！

長い記事となってしまいましたが、ここまでご覧くださりありがとうございました！
もし、この記事ひいては開発したアプリケーションが皆様のお役に立つことができたのなら幸いです。