railsとangularjsとbootstrapでwebサービスを作ってみた

railsとangularjsとbootstrapで[アップスワーク (AppsWork)](https://apps-work.com "AppsWork")というクラウドソーシングサービスを作ってみました。


## Webサービスを作った動機
下記記事のように現状のクライアントが圧倒的に強い、Win-Winになりにくい既存のクラウドソーシングの仕組みをなんとかできないかと考えたのが始まりです。
http://kosuke.cc/column/impression-of-lancers/

## この記事を書いた動機
作りながらでいいアイデアが浮かぶだろうと考えていたのですが、結局既存クラウドソーシングを覆せるようなアイデアは浮かばず簡易クラウドソーシングサービスのBeta版が完成してしまいました。

このままでは何も報われないので、使用した技術情報や開発の概要とソースを公開して社会に貢献できれば、と考えたのがこの記事を書いた動機になります。

## 開発について
使用した主な技術については下記になります。

* rails 4.2.0
* angularjs 1.3.14
* twitter-bootswatch-rails-3.3.4.0
* mysql 5.5?

rails(ruby)とangularjsとbootstrapはほぼ未経験の状態で開発を始めました。
開発期間は普通に仕事しながら時間を作って開発していたので、正確には分かりませんが、1.5人月ぐらいだと思います。

## 開発の流れ
おおまかに下記のような感じで開発しました。

1. htmlモック作成
1. railsのmodelの作成
1. 作成したhtmlモックのrailsへの組み込み
1. railsとangularjsのjsonのapi連携の確認
1. angularjsの構成の検討
1. 登録系画面のサンプル実装
1. 個別実装
1. 本番環境に反映

それぞれの作業概要、参考にした情報などを明記していきます。

## 1. htmlモック作成

まず必要機能の抽出と、ワーヤーフレームの草案を簡単に考えます。
その後、すぐhtmlモックの作成に取り掛かりました。

今回デザインでbootstrapを採用しましたが、bootstrapはほぼ初心者という状態でした。

まず構造的な事から把握しました。
グリッドレイアウト、レスポンシブ、フレックスデザインについて
http://designup.jp/bootstrap-css-performance-12/

次にどんなコンポーネントが使えるのか。
http://getbootstrap.com/components/

構造とそれぞれのコンポーネントの書き方が分かればhtmlとcssコーティングに移れます。
まず5ページぐらいのhtmlモックを作成しました。

## 2. railsのmodelの作成
railsも未経験なのでまずrailsについてどんなフレームワークかというのを把握しました。
参考にさせてもらったのは下記のような入門サイトです。
http://www.rubylife.jp/rails/

入門サイトを参考にmodelの作成まで終えました。
フレームワークはseaser2やcakephpなどの経験もあったので、すんなり学習できたように思います。
raillsは感覚的には同じ動的言語でかかれているcakephpに近いと感じました。

## 3. 作成したhtmlモックのrailsへの組み込み
モデルを作成するとviewも同時に作られるので、そこに作成したhtmlのモックを適用しました。
application.html.erbや_header.html.erb、_footer.html.erbなどで共通レイアウトも定義して、表示までを確認します。
http://www.rubylife.jp/rails/template/index2.html

bootstrapですが、bootswatchというjquery uiのテーマ切り替えようのな機能があるので、これを使いたいと思いました。調べるとrailsでbootswatchを使えるgemがあるようなので、下記を参考にさせてもらい組み込みました。
http://qiita.com/tsumekoara/items/1055879e1fb9d54b3059

これでrailsを動かしてブラウザでhtmlの表示まで確認できました。

## 4. railsとangularjsのjsonのapi連携の確認
angularjsも初心者ので、まずそちらを把握する必要があります。
下記のような入門サイトを参考にさせてもらいました。
http://8th713.github.io/LearnAngularJS/#/
http://dev.classmethod.jp/series/angularjs%E5%85%A5%E9%96%80/

一通り把握し、まずangularjsでコントロールを作成して簡単な双方向データバインドを行ってみました。
そして次にangularjsとrailsの連携を検討しました。

angularjsを使うとシングルページ構成になるので、railsの自動生成されるようなviewの構成ではそのまま使えません。くぐって探していると素晴らしい情報を投稿してくれているサイトを見つけました。
http://ruby-rails.hatenadiary.com/entry/20150120/1421761471

上記のサイトをほぼそのままの構成で使わせてもらいました。viewはtemplateに集約する事ができ、railsのviewへのレタリング機能も使えるので最適ではないかと思います。

基本的にrailsはapi提供のみで、クライアントサイドや画面周りはすべてangularjsに任せるようにします。

angularjsとrailsのAPI連携処理は下記を参考にさせてもらいました。
http://qiita.com/hkusu/items/b34f684b49751d9c9abd

railsはcsrfトークンが必要になるので、angularjsからのリクエストでは付与させるようにします。
http://qiita.com/kyohei8/items/21051cd586e057302559

またangularjsからrailsでMIME TYPE判別がうまくいかないので、下記を参考にさせてもらい対応。
http://qiita.com/sakatam/items/feff580add9b76e6f538

後、railsのturbolinksですが、angularjsがうまく動かない事があるので、無効にしました。

ここまで対応するとrailsとangularjsのjson連携がget,postなどで正常に動く事を確認できました。

## 5. angularjsの構成の検討
後々カオスにならないようにangularjsをview,controller,model,serviceでMVCフレームワークぽい構成にするように考えました。

まずservice.jsにrailsとのapi連携を集約しました。railsのモデル単位にangularjsのfactoryでサービスを作り、railsのget,post,put,deleteapiメソッドに対応するメソッドを定義します。処理はapiの呼び出しのみにします。

次にmodel.jsにrailsに対応するモデルを定義します。
複数のコントローラで変更を検知できるよう、下記のpub/subなどを参考にさせてもらい作成しました。
http://qiita.com/hkusu/items/b34f684b49751d9c9abd

angularjsコントローラはページヘッダーやフッターも参照可能になるMainControllerを親として、後はページ単位、ダイアログ単位にコンローラを作成する事にしました。必要なserviceやmodelはコントローラ単位で随時DIさせます。

angularjsのコントローラも継承が使えるので、AbstractControllerを一つ作り、共通で使用する処理はそこに実装する事にします。
http://blog.64p.org/entry/2014/01/20/114458

viewはrailsと同じようにページ単位でhtmlを用意します。

## 6. 登録系画面のサンプル実装
angularjsはバリデーションでも強力な機能があり、htmlに書くだけ実装でます。
http://tsuchikazu.net/angularjs-validation/

ただrailsでもバリデーションを実装する必要があります。
とりあえずは実装スピードを重視したかったので、rails側だけでバリデーションを定義する事にしました。
http://ruby-rails.hatenadiary.com/entry/20140724/1406145303

railsでバリデーションエラー時はerrorsにエラーメッセージが返されるので、それをangularjsに返すにようして、angularjsでは汎用的に処理できるようにAbstractControllerでエラーメッセージの設定をして、表示させるようにしました。

エラーメッセージはbootstrapのアラートに表示させるようにします。
http://jsdo.it/kazuki_nagasawa/bootstrap-001

## 7. 個別実装
サンプルで作った登録系画面を元に別の画面も作成していきます。
基本的にスムーズに他の画面も作成できました。
機能的に少し時間がかかったのは下記だと記憶しています。

[画像のアップロード]
画像のアップロードがあったので、下記を参考にng-uploadを使用する事にしました。プラグインの元ソースでangular.fromJsonでrailsからの戻り値をperseしている箇所があったのですが、そこでエラーになる事があった為、JSON.parseを使うようにだけ変更しました。
http://flabo.io/code/20141031/01-angularjs-compare-file-upload/

rails側では下記を参考にさせてもらっています。
http://dev.classmethod.jp/server-side/ruby-on-rails/ruby-on-rails_image_controller/

クライアントサイドでの画像圧縮、rails側でのRMagicを使用した画像圧縮など行った方がいいと思いますが、その辺はまだ対応できていません。

**メール送信** 
メール送信は下記などを参考にさせてもらい、ActionMailerを使用しました。
http://railsguides.jp/action_mailer_basics.html

**セッション管理**
セッション管理でログイン状態を保持する為などにgemのactiverecord-session_storeを下記などを参考に入れました。
http://easyramble.com/rails-active-record-session-store.html

**バッチ処理**
通知メールなどはデータで保持して、バッチ処理で定期実行させて送信させるようにしました。railsのバッチ処理は下記などを参考にtaskとwheneverを使用しています。
http://qiita.com/mosson/items/9a9b0703ac4c76ebfd4e
http://qiita.com/yumiyon/items/388fbb84450f49a6ab0d

**チャート描画**
円グラフなどを描画する必要があったので、chartjsを使用しました。
http://chartjs.org/

## 8. 本番環境に反映
一通りの実装が終わったので、本番環境に反映します。
サーバーのOSはcentosでWebサーバーはnginx、DBはmysqlでそちらは他のプロダクトで構築済みです。

まずrails関連を下記などを参考にさせてもらいインストールします。
http://qiita.com/shinyashikis@github/items/3501c5f7f71a8e345c3d

メール送受信が必要なので、下記などを参考にさせてもらいpostfixをインストールします。
http://centossrv.com/postfix.shtml

迷惑メール対策としてpostfixにSPFとDKIMの設定を行います。
https://blog.apar.jp/linux/856/
http://blog.jicoman.info/2013/08/postfix_spf_record/

railsを本番反映用にアセットプリコンパイルします。
http://qiita.com/ryounagaoka/items/8cbe76f2fb7a3157f07c

railsをgitからcloneして来て、nginxやunicornの設定などを行います。
http://qiita.com/Salinger/items/5350b23f8b4e0dcdbe23

後は個人情報も扱うので、nginxをsslに対応させます。
http://qiita.com/edo_m18/items/7e0e4b6d8e1e1d314184

ここまでで本番環境から対象Webサイトにアクセスができる事が確認できました。

## 最後に
rails(ruby)とangularjsとbootstrapはほぼ未経験の状態で開発を始めたので多少詰まった部分はありますが、現在ではこれをテンプレートとして他のプロダクトも作っており、スピード感を持って開発を進められています。

ソースは下記で公開していますので、よければ参考にしてみてください。
https://github.com/ychikugo/appswork

それでは！