Railsエンジニア初心者からの卒業

[Ateam cyma Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ateam-cyma)、1日目です！
トップバッターは [株式会社エイチーム](https://www.a-tm.co.jp) のエンジニア @u_minor3110 が務めさせていただきます。

早速ですがRailsを使うようになったけど、**どうなったらRailsエンジニアとして一人前なんだろう？一人前になれるんだろう？**と悩んでいる方、いらっしゃいませんか？そもそもスキルは定性的なもので計りづらいし、個人の目標であっても会社の業績に関わるものだったりして、なかなか実感を持てないかもしれません。そんな人のために、これらの機能の作り方を理解することができれば、とりあえず**Rails初心者からは卒業！**と言えそうなことを紹介したいと思います。なぜならこれらを理解できればそれなりの**WEBサービスを作ることができるから**です。
~~あとは教えるときにこれを見てくれれば個人的に楽できるかもしれない~~

なお、ruby gemを使った説明をしているところがありますが、gemは無数にあるので、ここで紹介するのはあくまで個人的見解でのオススメです。
また、gemに頼って機能の仕組みの理解をおろそかにするのも本当はよくないと思っています。ゼロからその機能を作ってみると、さらにレベルアップに繋がると思います。

## ツールのバージョン
* ruby 2.6.5
* Rails 5.2.3

## これだけ覚えておけば簡単なWEBサービスが作れるよ！な機能達

* 認証機能
  * 権限機能
* レコードのCRUD
  * データ検索
  * ページング
  * CSVダウンロード
  * 入力フォーム
  * CSVアップロード
* メール送信
* サンプルデータ作成
* 自動テスト
* デプロイ
* コード整形
* デバッグ用、チューニングのツール

## 認証機能の作り方

認証機能は、メールアドレスやユーザ名などとパスワードを使ってログインし、ログインできた人だけに機能を提供するような処理を作りたいときに使います。
これを実装するには**devise**というgemを使うのがオススメです。内部管理用とお客様用という感じで異なるユーザで別々の認証処理が必要な時も割と柔軟に対応することができます。githubでのwikiが充実しているので、わからない事も大抵書いてあります。（英語で）

* [devise](https://github.com/plataformatec/devise)
* **できてほしい事**
    * メアドとパスワードによるログイン
    * ログインしたユーザのみ機能が利用できる
    * パスワードの変更
    * メアドではなく一意のユーザ名でのログイン
* **これができるとさらに良い！**
    * メールを使ったユーザの認証
    * 内部管理用とお客様用といった、異なる2つ以上のユーザの認証処理
    * ldapによるアカウント連携を使ったログイン
    * より高度な認証方法の実装

## 権限機能の作り方

権限機能は、ログインした後にさらにログインした人によっては使える機能に制限をかけたい、というときに使います。adminユーザは全部使えるけど、guestユーザは参照しかさせたくない、といった感じです。
これを実装するには、**rolify**と**pundit**というgemを使うのがオススメです。一般的なCRUDに対して制限をかけるだけでなく、独自のアクションに対しても制限をかけられます。また、レコード一覧を表示するときに、そのユーザが作成したデータだけを表示させる、なんて事もできます。

* [rolify](https://github.com/RolifyCommunity/rolify)
* [pundit](https://github.com/varvet/pundit)
* **できてほしい事**
    * ユーザにロールを割り当て、ロール別に実行できるアクションを制限できる
        * 権限がないユーザには、当該アクションのリクエスト時にエラーを出す
        * 権限がないユーザには、当該アクションへのボタン、リンクを無効にする
* **これができるとさらに良い！**
    * 自身が作成したレコードのみを更新したり参照する事ができる

## レコードのCRUD機能の作り方

内部管理用でマスタメンテナンス画面を作ることは必ずと言っていいほどあるでしょう。こちらもrails_adminやactive_adminといったgemがありますが、正直Railsが標準で持っているscaffoldコマンドで実装する方法で十分です。
他のgemもそうですが、特に管理画面系のgemは安易に異なるプロジェクト間で別々のgemを使ってしまったりするので、gemが違った場合に覚える事が多くなってしまいます。
scaffoldはベースとなるテンプレートをカスタマイズする事もできるので、bootstrapやblumaといったcssフレームワークを使いたい時も、一度テンプレートをカスタマイズしてしまえば、以降generateされるテンプレートを修正する必要もありません。

* シンプルにscaffoldで作ろう

```ruby
rails generate scaffold ...
```

* **できてほしい事**
    * scaffoldコマンドの実行
    * レコードの検索（次のサブタイトルに詳細が続きます）
    * ページング（次のサブタイトルに詳細が続きます）
    * CSVダウンロード（次のサブタイトルに詳細が続きます）
    * 入力フォーム（次のサブタイトルに詳細が続きます）
* **これができるとさらに良い！**
    * CSVアップロード（次のサブタイトルに詳細が続きます）
    * 親子関係にあるテーブルの同時メンテ
    * scaffoldテンプレートのカスタマイズ
    * 更新履歴の保存

### レコードの検索

indexページではレコードの一覧が表示されますが、レコード数が多いと検索機能が欲しくなります。そんなときは**ransack**というgemを使うのがオススメです。検索フォームと合わせて検索処理を作るのが驚くほど簡単です。
基本は対象テーブル内のカラムだけが簡単に検索できるのですが、別テーブルのカラムを検索条件としたい、といった独自の検索条件も、ransackable_scopesメソッドを使えば簡単に対応できます。
カラムを指定してソート順を変更する仕組みも、ransackが用意するsort_linkメソッドを使えばこちらも簡単に実現できます。

* [ransack](https://github.com/activerecord-hackery/ransack)

### ページング

同じくindexページではレコード数が多いと、全部のレコードを一度に表示せず、数十件のレコードに分けて表示させたいときがあります。そんなときは**kaminari**というgemを使うのがオススメです。
modelによって１ページに表示する件数を変えたり、現在全部で何件中の何件を表示しているかの情報も簡単に表示する事ができ、cssフレームワークへの対応もページング用テンプレートのgenerate時にする事ができます。

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

### CSVダウンロード

対象のテーブルによっては、レコードをCSVファイルなどでダウンロードしたいときがあります。
こちらはgemは不要で、indexアクションを拡張すれば簡単に実装ができます。
actionは以下のようにして、index.csv.rubyテンプレートを用意してあげれば処理は完成です。
（※以下の例はransackとkaminariのgemの使用を想定して書いています。model名はよしなに。）

```ruby:foos_controller.rb
def index
  @q = Foos.ransack(params[:q])
  respond_to do |format|
    format.html { @foos = @q.result.page(params[:page]) }
    format.csv { @foos = @q.result }
  end
end
```

### 入力フォーム

* scaffoldで作成したものは、管理者画面用には良いですが、ユーザ向けには向いていなかったりします。そうなるとどうするか。こちらは長くなるので次回に・・・

### CSVアップロード

対象のテーブルによっては、ファイルから一括登録を行いたいときがあります。createやupdateとは別のアクションを作成して対応することになります。
１行ずつ読み込んでsaveするところまでは想像できると思いますが**activerecord-import**というgemを使えば、まとめてsaveする事が可能となり、レコード数が多くなるにつれて飛躍的に処理速度が上がるので覚えておきましょう。

* [activerecord-import](https://github.com/zdennis/activerecord-import)

## メール送信

お客様が入力フォームに記入して申し込みをした際に、申し込み完了メールを送りたいときがあります。
こちらはRails自前の機能を使えば基本的に事足ります。
また、開発環境ではメールをいちいちメールサーバで受けとって確認したくないよ、あるいは間違ってお客様宛にメールを送りたくないよ、なんて時は**letter_opener** gemを使うのがおすすめです。
さらにはActiveJobと連携する事で、登録してから5分後にメールを送る、なんて事も可能です。

* Action Mailerを使おう（https://railsguides.jp/action_mailer_basics.html）
* [letter_opener](https://github.com/ryanb/letter_opener)
* **できてほしい事**
    * メールを送る事ができる
* **これができるとさらに良い！**
    * 非同期処理でメール送信を行う事ができる

## サンプルデータ作成

マスタとなるデータを作成したい、あるいは開発用にダミーデータを用意して共有したい、そんな時は**seed_fu**というgemを使うのがおすすめです。
さらには例えばダミーのメールアドレスを作成するにしても、適当なデータを考えるのが面倒な場合は、**faker**というgemを使えば簡単に適当なデータを作る事ができます。
他にはcapistrano gemと連携してデプロイ時に本番DBにマスタデータを追加する、なんて事もできそうです。（試してない）

* [seed_fu](https://github.com/mbleigh/seed-fu)
* [faker](https://github.com/faker-ruby/faker)
* **できてほしい事**
    * 各テーブル毎にダミーレコードを用意する

## 自動テスト

仕様書書いてますか？・・・その前に新しい仕様が追加されてしまう？それならばテストを書きましょう。スピードが最優先の場合テストは後回しにされがちですが、複雑なシステムであれば間違いなく最初からテストは作成するべきです。でないと後から関わった人がとっても辛い目に会います。
jsを駆使したようなリッチなUIを備えているならば、E2Eテストも必須になってくるでしょう。
テストによく使われるのは**rspec**というgemです。modelクラスだけでもテストが書けられたら幸せです。
なおrspecの書き方はこちらをご参考に。-> http://www.betterspecs.org/jp/

* [rspec-rails](https://github.com/rspec/rspec-rails)
* [factory_bot_rails](https://github.com/thoughtbot/factory_bot_rails)
* **できてほしい事**
    * modelクラスのテスト作成
* **これができるとさらに良い！**
    * E2Eテストの実装

## デプロイ

開発環境で完成したプログラムを本番環境用のサーバにリリースしたい、そんな時は**capistrano**というgemを使うのが一般的です。これまでの機能とは違い、デプロイ先のサーバの指定や、ソフトリンクさせるファイルやフォルダの指定など異質な感じがしますが、ぜひ覚えましょう。
会社ですでに設定されていて難しい場合はレンタルサーバを借りてとにかく試す！のがおすすめです。

* [capistrano](https://github.com/capistrano/capistrano)
* **できてほしい事**
    * 本番用のサーバに作ったプログラムをリリースする事ができる
* **これができるとさらに良い！**
    * リリース処理の合間に独自の処理を追加する事ができる
 
## コード整形

複数人で開発をしなくとも、プログラムのメンテナンス性を高めるために、コード規約を設けて統一感のある書き方をするのは非常に有用です。そんな時**rubocop**というgemを使えば規約を統一する事ができ、規約と書き方が間違っている部分を探し、自動で補完をしてくれたりします。

* [rubocop](https://github.com/rubocop-hq/rubocop)
* **できてほしい事**
    * プロジェクト要件に応じたrubocopの設定

## デバッグ用、チューニング用ツール

プログラムの質を上げたり開発のスピードをあげるには、デザインパターンを知っているだけでなく、デバッグや分析用のツールを入れておく事も重要です。こちらも様々なものがありますが、代表的なものをあげていきます。
**pry** gemは処理を途中で止めてステップ実行をしながらデバッグするためのgemです。変数に正しい値がセットされているかどうかを確認したり、ビジネスロジックが正しく動くかを確認したりします。pry-byebugやpry-docなどの関連gemを使えばより細かいチェックを行う事ができます。
**bullet** gemはN+1問題を解決してくれるためのgemです。N+1とは一言で言えば省略できるDBアクセスが発生している状態です。bulletはN+1が発生した時にどのテーブルをあらかじめ読み込めば、DBアクセスを減らせるかを教えてくれます。設定によってその内容をアラートウィンドウで表示させたり、ログに出力させたりできます。
**rack-mini-profiler** gemはどのクエリに何秒かかり、ページ表示にどれくらい時間がかかったかを教えてくれます。遅いクエリに対してindexの追加を検討するのに使ったりします。

* [pry](https://github.com/pry/pry)
* [bullet](https://github.com/flyerhzm/bullet)
* [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler)
* **できてほしい事**
    * ステップ実行によるデバッグ
    * N+1の解消
* **これができるとさらに良い！**
    * 適切なtable indexの追加

## まとめ

入力フォームの説明が抜けてはいますが、これらが基本的なWEBサービスの機能になると思います。
これらは簡単なようで、実際は業務に携われずに実装方法がわからなかったりします。
そんなときはなんでもいいので個人的にサービスを作ってみましょう！
rails guideだけでは足りない部分の参考にと思っていただければ幸いです！よきRailsライフを！

## 終わりに

[Ateam cyma Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ateam-cyma)の1日目、いかがでしたか。
2日目は@hibiheionさんがRubyMineについて話をしてくれますのでお楽しみに！

株式会社エイチームでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。

エンジニアで興味を持った方は[cymaのQiita Jobs](http://bit.ly/35E1I08)をご覧ください。

そのほかの職種は、[エイチームグループ採用サイト](http://bit.ly/2XQpd3q)をご覧ください。