RailsとReactでオンライン予約表QRnoteを作って公開した話

# 概要
* [QRnote](https://qrnote.work)は誰でも使えることが特徴のオンライン予約表です
* Rails + React + Dockerで開発し、Elastic Beanstalkで公開しています
* ソースをGitHubで[公開](https://github.com/junara/qrnote)していますので、記事内のライブラリの紹介とあわせてご参照ください!

# まず使いたい！
## いますぐ試したい
* https://qrnote.work

## ローカルで動かしたい
* https://github.com/junara/qrnote をクローン。
* Dockerで開発していますので、下記のcommandでを実行して起動して下さい。 https://localhost:3000 にQRnoteが起ち上がります。

```
docker-compose build
docker-compose run web yarn install
docker-compose run web rails db:create
docker-compose run web rails db:migrate
docker-compose up
```

* 終わるときは、`docker-compose down`

# 自己紹介
## エンジニア歴
* 1977年生まれの40歳。その他[こちら](https://techacademy.jp/blog/47)と重なるので省略
* 2016年6月からWebエンジニアとして働き始めました
* 普段からRails, Reactのお仕事やっています

# QRnoteの紹介
* 無料のオンライン予約表です
* 2日後まで予約できます

[![https://gyazo.com/4c9a2654bf5c809cc74689b34de28d55](https://i.gyazo.com/4c9a2654bf5c809cc74689b34de28d55.png)](https://gyazo.com/4c9a2654bf5c809cc74689b34de28d55)

## 開発期間

* 2017年11月から4ヶ月ぐらい

## 特徴

* 誰でもすぐ使える

## 開発のきっかけ
会社勤めしていると社内共通の備品ってありますよね。それらの使用頻度が増えたときに登場する紙の予約表。（備品の横に置かれた**EXCELでつくって印刷した紙のカレンダー**とか）

2018年なのに未だ手書きって・・・・と感じていたのでつくりました。

## 備品予約表の問題は？

### 備品予約を紙のカレンダーで管理するとやはりめんどい
* 予約参照する場合→備品のところまで歩いて行って目視で確認→めんどい
* 予約する場合→紙のカレンダーに手書きで名前を書き込む→めんどい

### 備品予約表をgoogle スプレッドシートとかExcelで作ってみるけどめんどい
* google driveにおいてアクセス→PCからアクセスできる→カレンダー表作るのめんどい

### 備品予約表をgoogle calendarとかoutlookで作ってみるけどめんどい
* google calendarとかoutlookカレンダーを共有する→カレンダーにアクセスできるけどアクセス権考えるのめんどい

### めんどくない予約表を作ろう
* さくっと公開、誰でもすぐ使えるオンライン予約表を作ればめんどいが世の中からへってうれしいかも

# 仕様
## 無駄な機能は省こう
[調整さん](https://chouseisan.com/)いいサービスですよね。無駄な機能がないので使いやすい。

これを手本に、まず**実装しない機能を決めました**。

* アクセス権制御（承認）は実装しない←知り合い同士なら性善説でいいじゃん
* ログインログアウト機能（認証）は実装しない←そこまで秘密にするほどの情報じゃないならそこそこでいいじゃん
* ユーザーの排他制御は実装しない←予約状況がみえれば、適宜判断すればいいじゃん
* 分単位で予約機能は実装しない←分刻みの稼働してないじゃん


## 実装する機能
* 新規予約表作成&固有UUID付与
* 認証：予約表固有UUIDを知っているか否か
* 承認：なし（固有UUIDを知っているユーザーは全機能使える）
* 予約CRUD
  * 予約作成：予約は名前を書くだけにする。予約時間帯は30分刻み固定。
  * 予約表示：当日含む3日間。
  * 予約更新：実装しない
  * 予約削除：実装

# コード解説
## 構成概要
RailsでAPIつくってReactで表示するシンプルな構成です。

* Rails: > 5.1
* React: > 16

## 使ったライブラリと説明
### Rails
全般的には、[こちらの記事](https://qiita.com/seri_k/items/605e6f75da838ae00007)を参考にしました。


#### API
APIの作成はjbuilderです。ざっくりつくるのに、自由度高くAPIが設計できるところが好きなので選択しました。

他の候補は、[active_model_serializers](https://github.com/rails-api/active_model_serializers)と[fast_jsonapi](https://github.com/Netflix/fast_jsonapi)。これは、次回以降のアプリでやります。

特に、fast_jsonapiはactive_model_serializersよりも25–40x speed！なんて[書かれている](https://medium.com/netflix-techblog/fast-json-api-serialization-with-ruby-on-rails-7c06578ad17f)ので次回以降のアプリで積極的使いたいです。

* 参考にしたサイト
    * https://qiita.com/hmuronaka/items/c4e365cc0a9d465731f8
    * https://qiita.com/kakkunpakkun/items/1c23b936d13f08a42752
    * https://blog.onk.ninja/2017/09/21/history_of_json_api_with_ruby

#### メタタグ
定番の[meta-tags](https://github.com/kpumuk/meta-tags)。それ以外知らない。

* 参考にしたサイト
    * https://qiita.com/tomomomo1217/items/912afba852dc524d748e 
    * https://qiita.com/pompom0c0/items/5c00a188aab744cfc918
    * http://vdeep.net/rubyonrails-meta-tags-seo

#### 定数管理
[config](https://github.com/railsconfig/config)つかっています。[dot env](https://github.com/bkeepers/dotenv)よりもymlで階層的に管理できるので好み。

* 参考にしたサイト
    * https://qiita.com/yumiyon/items/32c6afb5e2e5b7ff369e
    * http://vdeep.net/rubyonrails-config-gem

#### サーバー監視
認証機能がないので、過剰なリクエスト（特にpost）をはじくため、[rack-attack](https://github.com/kickstarter/rack-attack)を導入しています。

* 参考にしたサイト
    * https://qiita.com/patorash/items/57f9f70ca00952e39f37
    * http://kitak.hatenablog.jp/entry/2014/10/06/205713
    * https://github.com/kickstarter/rack-attack/wiki/Example-Configuration

あと、念のため、[impressionist](https://github.com/charlotte-ruby/impressionist)でIPをDBに記録しています。ただ、これは不要だったかも。

* 参考にしたサイト
    * https://qiita.com/yimajo/items/995584ede90be1a873ce

#### 例外処理
特別なライブラリはないです。

[こちらの記事](http://morizyun.github.io/blog/custom-error-404-500-page/)を参考にしました。

他にもあったのですがリンクメモしていない。すみません。

### React
この記事を書き始めたときに、このQiitaの記事「[React Redux の SPA を運用して得られた知見と実装例、開発フローもあるよ！](https://qiita.com/numanomanu/items/af97312f34cf1388cee6)」が出ました。素晴らしい記事です。すごいわかりやすいので、ぜひみんな読むべき。

0からReactでSPAを書いた身として、この記事が一番まとまっている思いました。個人的には、読後、HOCが使いたくなりました。HOCでダイアログDryに書き直したい。

いい記事公開の直後なので、お恥ずかしいですが、react の SPAの一例として捉えて読んでください。

#### state管理
[react-redux](https://github.com/reactjs/react-redux)。王道。バケツリレーしたくない。

モデルを[immutable](https://facebook.github.io/immutable-js/)のrecordで作りました。recordを使うと、railsのmodelっぽくstateを扱えるコードを書くつらみが、かなりなくなります。強くオススメ。

* 参考にしたサイト
    * http://post.simplie.jp/posts/81
    * http://dackdive.hateblo.jp/entry/2017/04/24/133955

ミドルウェアは[redux-saga](https://github.com/redux-saga/redux-saga/blob/master/README_ja.md)。他の候補は、[redux-thunk](https://github.com/gaearon/redux-thunk)。redux-thunkは軽く導入できるので、最初redux-thunkを作っていました。しかし、書き続けるとreducerが肥大して行く感じがしたので、早々に、redux-sagaに変更しました。

redux-sagaはとっつきにくいです。使い方を理解するまで、1週間ぐらいかかりました。でも、苦労する甲斐はあるとおもう。非同期処理をキレイに分離できます。

* 参考にしたサイト
    * https://qiita.com/kuy/items/716affc808ebb3e1e8ac まず最初に目を通すべき。
    * https://qiita.com/mpyw/items/a816c6380219b1d5a3bf 色々戦って読むとすごくうなづける
    * https://medium.com/@marcelschulze/using-react-native-with-redux-and-redux-saga-a-new-proposal-ba71f151546f これも色々戦った後に読むと楽しい。

#### ページ遷移
[react-router](https://github.com/ReactTraining/react-router)。これも王道。[公式のドキュメント](https://reacttraining.com/react-router/)が豊富なのでそれを読めば使える。

V4で大きく変更があったみたいなので、新しいドキュメントを参照すること推奨。

* 参考にしたサイト
    * https://qiita.com/hoture/items/b4ca1773580317e7112e

#### HTTPクライアント
[axios](https://github.com/mzabriskie/axios)。他の選択肢は、[superagent](https://github.com/visionmedia/superagent)と[fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch)。特に、fetchは公式のAPIなので迷いました。しかし、最終的にはドキュメントの豊富さからaxiosを採用しました。

* 参考にしたサイト
    * https://qiita.com/sukechansan/items/738b4bdaffc07c337a70
    * http://www.yoheim.net/blog.php?q=20170801

#### CSSフレームワーク
[material-ui v1.0.0-beta](https://material-ui-next.com/)。マテリアルデザインにすることは決めていました。その中で、reactでマテリアルデザインを実現するフレームワークでもっともメジャーだった、material-uiを選択しました。

他のフレームワーク候補は[こちら](https://material-ui-next.com/getting-started/comparison/)。

material-ui、かなりオススメです。ドキュメントが豊富なので、それをそのまま使うだけでどんどん機能が実装できます。また、デモコードを読んだり、material-ui自身のソースを読むととても勉強になります。今回のアプリのソースは、8割以上material-ui（とドキュメント）のおかげ。

* 注意点
    * materia-uiは現在ベータ版。breaking changeが高頻度で入ってくるので、安易なyarn upgradeはしない方がいい
       * 実際この記事を書く前にbreaking changeがあったので、急遽コードの修正をした
    * material-uiの1.0 betaと0.xは全く仕様が異なる。古い記事は参考にしづらい。
    * （material-uiの本質じゃないけど）CSS in JSは便利。だけど、とっつきづらい。

* 参考にしたサイト
    * https://qiita.com/sakana/items/44ccc364bc3fad5ae6de
    * https://qiita.com/vimyum/items/f89b963b7f253237e482

#### 日付処理
[date-fns](https://github.com/date-fns/date-fns)。他の候補は[moment](https://momentjs.com/)。momentがメジャーで機能が豊富ですが、date-fnsを選択。

date-fnsにした理由は、immutableだから。ruby(rails)のTimeとかActiveRecordと同じ感じで使えてき気持ち良いです。

* 参考にしたサイト
    * https://date-fns.org/ 公式だけどほぼこれでOK
    * https://www.webprofessional.jp/date-fns-javascript-date-library/ これ読んでdate-fns導入を決めた

### その他
機能の根幹ではないけど、その他使ったライブラリを紹介します。

#### QRコード表示
最近、[電脳コイル](http://www6.nhk.or.jp/anime/program/detail.html?i=coil)見てるというのもあるのですが、グラス型デバイスを調べています。日本の[QDレーザー](http://ascii.jp/elem/000/001/428/1428515/)とか、[Appleが開発中との噂](https://corriente.top/apple-ar-glass-concept/)もあります。グラス型のデバイスが日常にやってくるのも遠くなさそう。

今回、各備品には固有のQRコード画像をつけました。ユーザーがQRコードをテプラなどで印刷したシールを備品に貼って、スマホのカメラでスキャンする未来を期待してます。電脳コイルの世界にちょっとでも近づきたいと思って。

[![https://gyazo.com/f4c3d38750d01039af30300469227b78](https://i.gyazo.com/f4c3d38750d01039af30300469227b78.png)](https://gyazo.com/f4c3d38750d01039af30300469227b78)

* 使い方のイメージの参考
    * [社内の備品貸出にTSUTAYAのレジ風システムを導入した](https://qiita.com/tabbyz/items/f42840504ecc6ff4f827) 
    * [QReserve Mobile Library](https://www.youtube.com/watch?v=LxdBWUyxuxs)
* 実装に使ったライブラリ
    * [react-qr-svg](https://github.com/no23reason/react-qr-svg) SVG形式で、QRコードをで出力できるのがいい。
    * [rqrcode](https://github.com/whomwah/rqrcode) サーバー側でQRコード画像生成

#### コピペ
URLをクリップボードにコピーできるボタンを作成するために使用。

[![https://gyazo.com/938dd3719cbd6b6008488c4a564b420d](https://i.gyazo.com/938dd3719cbd6b6008488c4a564b420d.png)](https://gyazo.com/938dd3719cbd6b6008488c4a564b420d)

* [react-copy-to-clipboard](https://github.com/nkbt/react-copy-to-clipboard)

#### 画面のスクロール制御
任意の場所（refsで指定）に移動するために使用。

* [react-scroll-to-component](https://github.com/flyingant/react-scroll-to-component)

#### シェア
シェアボタン

* [react-share](https://github.com/nygardk/react-share) facebookなど定番のシェアボタンの作成に使用した。

      [![https://gyazo.com/4e0c0a3db2c2919858556ffed5da508c](https://i.gyazo.com/4e0c0a3db2c2919858556ffed5da508c.png)](https://gyazo.com/4e0c0a3db2c2919858556ffed5da508c)

* [list-it](https://github.com/takamin/list-it) 予約状況を下記の様なテキスト形式の表を出力するために使用した。


```example_mail.txt
現時点の予約者リスト

02/19(月) 午後03:00-03:30 平松光叶
02/19(月) 午後03:00-03:30 篠原武瑠
02/21(水) 午後02:00-02:30 広瀬一平
02/21(水) 午後05:30-06:00 及川萌風
```

#### iCalカレンダ出力
iCalendar形式で出力するために使用した。railsの定番。

[![https://gyazo.com/cc92dd79eb8125a624e794d6445cb76b](https://i.gyazo.com/cc92dd79eb8125a624e794d6445cb76b.gif)](https://gyazo.com/cc92dd79eb8125a624e794d6445cb76b)


* [icalendar](https://github.com/icalendar/icalendar)

* 参考にしたサイト
    * [Webcal Links in Rails with the icalendar Gem](http://www.toasterlovin.com/rails-webcal-links-with-icalendar-gem/)
    * [RailsでiCalendar形式で予定を公開する](https://programming.wikihub.io/@r7kamura/20160627030457)

#### アニメーション
UXを良くするために導入。

[![https://gyazo.com/075af2da64aeb4e82058503801477a61](https://i.gyazo.com/075af2da64aeb4e82058503801477a61.gif)](https://gyazo.com/075af2da64aeb4e82058503801477a61)

* [react-countup](https://github.com/glennreyes/react-countup) 予約者数をカウントアップしてアニメーションするために使用した。
* [velocity-react](https://github.com/google-fabric/velocity-react) 予約者のchipsをふわーっと表示するために使った。囲めばいいだけなので、使いやすい。
    * [参考](https://qiita.com/59naga/items/965fa72333c07cd538e0)
* [react-loading](https://github.com/fakiolinho/react-loading) fetching中を示すためのアニメーション

#### メモ機能
メモ機能の実装のために導入。サーバーサイドでやるのはコストが高いので、クライアントでmarkdown変換してもらうことにした。

* [react-markdown](https://github.com/rexxars/react-markdown) メモを残す機能を実装するために使用。

#### デモ用のランダムデータ作成
デモデータを出力するためのランダムデータ用に導入。日本語のデモデータってあまり種類ないですよね。

[![https://gyazo.com/01b61f5ddee925a430476919ac8b9924](https://i.gyazo.com/01b61f5ddee925a430476919ac8b9924.gif)](https://gyazo.com/01b61f5ddee925a430476919ac8b9924)

* [faker](https://github.com/stympy/faker)、[gimei](https://github.com/willnet/gimei) 日本語姓名のランダムデータ作成に使用。

## deploy
### AWS ElasticBeansTalk
Herokuとどちらにするか迷ったけど、HTTPS化するのが楽ちんなので、AWSにしました。

* 参考にしたサイト
    * http://blog.wackwack.net/entry/2017/02/07/223956 非常に丁寧に説明されています。HTTPS化の所とか、ここまで優しく手順が示されているのはすごい。

* 関連の拙記事
    * https://qiita.com/junara/items/ae09c94da5223c9c3aff AWSの導入まで
    * https://qiita.com/junara/items/8eb501b855697fedc42e Encrypted Secretの使い方
    * https://qiita.com/junara/items/62b0e11f71111ef8e4ce ドメイン取得と反映

# 感想
実装しない機能を決めるのすごい大事。デザインも楽になるし、使いやすくなるし、リリースも早くできるのでいいことづくしです。特に、個人開発だとだらだらしちゃうので、リリースが早くできるのは大きな利点です。

また、すべて公開（今回であれば、GitHubソース公開とQiitaへの記事投稿）をゴールにしたのもよかったです。Outputする過程で知識が定着することを実感できたので楽しいです。