gem嫌いでも使っているgem

# 0. はじめに
私は基本的にgemを使うのは好きではありません。個人で開発されているものであれば、いつメンテナンスが終わるかもわかないし、メンテナンスが終わったときに自分がメンテをし続ける自信もありません。もともとデータベース設計に関してはRailsエンジニアになる前から勉強してきたので、データベース設計が絡むgemに関しては躊躇することが多いです。
そんなgem嫌いな私でもgemを使わずにRails開発することは不可能です。今回は、それなりに使ってきてこれは使えると思ったものを私の経験ベースで紹介したいと思います。
pgやslim-railsなど、postgreSQLやslimを使うならこれがないとダメでしょといったものや、pry, rspec-rails, factory_bot_railsなど定番なものを除いています。
思いついたときに逐次追記していきます。

# assets系
## [sassc-rails](https://github.com/sass/sassc-rails)
Railsで何も考えずにsassを使うときは、sass-railsだと思うのですが、だんだん重くなってきます。assets:precompileに時間がかかったり、sassを編集した後の開発時のリロードが遅くなったときに手を打ちやすい方法がsassc-railsを使うことです。sass-railsはruby実装ですが、sassc-railsはc実装なので処理が早いです。まれに、sass-railsで問題なかった記述がsassc-railsでエラーとなることがあるので、最近では初期の段階からsassc-railsを導入するようにしています。

# フロントエンド連携系
## [gon](https://github.com/gazay/gon)
サーバーサイドとフロントエンドの値の受け渡し方法はajaxでとってくるなど、いくつか考えられますが、gonはその方法の一つです。renderした段階で値が決まっている場合は便利かと思います。

## [draper](https://github.com/drapergem/draper)
例えば、モデルのカラムの値をそのままではなく、少し編集をして表示させたいと言った時などに利用します。ビューの表示のためにモデルにメソッドを追加したくないという場合に重宝します。デコレーターパターンの実装法の一つです。

```ruby
# 一つのActiveRecordをdecorateする場合
@article = Article.first.decorate
## or
@article = ArticleDecorator.decorate(Article.first)

# collectionオブジェクトの一つ一つをdecorateする場合
@articles = Article.all.decorate

# collectionそのものをdecorateする場合
@articles = ArticlesDecorator.decorate(Article.all)
## collectionそのものをdecorateした場合のDecoratorの実装例
## ビューのみに利用する集計などで利用した経験がありますが、viewのrender時に実行されるのであまり良くないかも。
class ArticlesDecorator < Draper::CollectionDecorator
  # objectでcollectionを参照することができる。
  def total_count
    object.count
  end

  def latest_created_at
    object.order(created_at: :desc).first.created_at
  end
end
```
記事投稿時点では、draperを使っていましたが、結局、モデルが小さければモデル内のメソッドで定義、viewだけで使うということを明示したい場合は、concerに逃すと言った方が実用的と感じ2024年4月現在ではdraperを選択することはほぼなくなりました。一見してdecorateしているかを把握することも面倒です。また、viewだけで使うと思ったらview以外でも使う必要が出てきたということもあるので、draperの問題というより、デコレーターパターンのメリットを感じなくなってきたのが理由です。

# データベース系
## [activerecord-import](https://github.com/zdennis/activerecord-import)
RailsでBULK INSERTするにはどうすればいいかなと思ったときに役に立つのがこのgemです。ただし、Rails6以上からは標準でサポートされました（`insert_all`や`upsert_all`など）ので、不要になってくると思います。

## [paper_trail](https://github.com/paper-trail-gem/paper_trail)
以前、リレーショナルデータベースでの履歴管理を真剣に考えたことがあるのですが、リレーショナルデータベースにおいて履歴管理は苦手分野の一つで結構苦戦して、結局このgemにたどりつきました。
レコードの履歴管理の定番のgemだと思います。yaml形式やjson形式で差分を表示してくれます。jsonをサポートしているデータベースであれば、json形式で保存できるのは便利です。

## [auto_strip_attributes](https://github.com/holli/auto_strip_attributes)
フォームからレコードを生成する場合、例えば任意項目などでテキストフィールドに入力が不要な場合、`params`には次のような形で入ってきます。注目は`corporate_name`でここが任意の場合、空文字できます。そうすると、レコードには空文字で保存されてしまいますが、`null`（rubyでは`nil`）で保存して欲しいです。

```ruby
<ActionController::Parameters {"order"=><ActionController::Parameters {"family_name"=>"てすと", "given_name"=>"太郎", "corporate_name"=>""} >
```
この時に便利なのがこのauto_strip_attributesで、モデルに次のように記述すると空文字を自動で`nil`に変換してくれます。

```ruby
class Order < ApplicationRecord
  auto_strip_attributes :family_name, :given_name, :corporate_name
end
```

## [carrierwave](https://github.com/carrierwaveuploader/carrierwave)
画像アップロードとかができます。Rail5.2からは[ActiveStorage](https://railsguides.jp/active_storage_overview.html)が追加されたので、そちらに移行していくのだろうと思いますが、carrierwaveの功績は大きいかと思います。

# 通信系
## [typhoeus](https://github.com/typhoeus/typhoeus)
libcurlのラッパーです。インタフェースが比較的わかりやすく、並列実行もできるので良く利用しています。

## [active_elastic_job](https://github.com/tawan/active-elastic-job)
ElasticBeanstalkでworkerを利用した時のActiveJobの具体的な実装の一つです。ElasticBeanstalkには環境枠（environment tier）として、webとworkerがあるのですが、worker単独での利用でもいいですし、webとworkerを連動したいときに利用します。[GitHub](https://github.com/tawan/active-elastic-job)のREADEMEが詳しいのがありがたいです。

# 認証系
## [sorcery](https://github.com/Sorcery/sorcery)
devise（やwarden）に悩まされた人も多いはず。sorceryは、シンプルさを保って実装されており、比較的軽量なgemです。にもかかわらず、ログイン・ログアウト情報や、セッションタイムアウト、ブルートフォースアタック対策など嬉しい機能があります。詳しくは[sorceryのwiki](https://github.com/Sorcery/sorcery/wiki)をご覧ください。
シンプルさを保つため、複数モデルには対応していないのがちょっと困るかもしれません。

# テスト支援系
## [parallel_tests](https://github.com/grosser/parallel_tests)
テストを並列・平行実行してくれます。たとえばCircleCI2.0では１コンテナあたり2CPUなので2つまで並列実行するとほぼ確実に高速化します。（3並列以上だと必ずしも速くなるとは限りません。）
コマンドの実行の仕方は`-n`オプションで並列・平行数を指定します。CPUの数より大きい値を指定した場合は、よしなに平行実行されますが、IO待ちなどがない限り、スピードは上がらないかもしれません。
Rails6ではテストの並列実行ができるようになる予定です。[^1] そうなれば、このgemは不要になるかもしれません。
[^1]: https://github.com/rails/rails/pull/31900

```bash
bundle exec parallel_rspec -n 4
```
## [rspec-retry](https://github.com/NoRedInk/rspec-retry)
rspecでテストが失敗したとき、リトライしてくれます。リトライ単位は`it`や`scenario`です。feature specやsystem specではNetTimeoutやJavascriptの微妙な挙動でランダムで失敗したりします。１回の失敗ごときで失敗するな！もう一度実行して成功したら成功とみなしてもよいというテストケースにはリトライを仕込むと良いでしょう。

# 開発支援系
## [rails-erd](https://github.com/voormedia/rails-erd)
私はER図が好きなので、Railsの中で適切にリレーション（has_manyなど）を設定してあげれば、よしなにいい感じのER図を描いてくれるこのgemの存在は大変ありがたいです。

## [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler)
処理速度を知ることができます。ボトルネックを探したいときに重宝します。

## [sitemap_generator](https://github.com/kjvarga/sitemap_generator)
SEO対策の基本の一つがsitemap.xmlを作成することです。rubyには、[sitemap_generator](https://github.com/kjvarga/sitemap_generator)というgemが非常に便利です。

```
rake sitemap:refresh
```
でsitemap.xml.gzを作成しGoogleやbingにpingも飛ばしてくれるのですが、開発時にはpingは飛ばして欲しくありません。

```
bin/rake -vT | grep sitemap
```
でsitemap_generatorのrakeタスクが見れますが、開発時によく使うのは、検索エンジンにpingを飛ばさずにsitemap.xmlを作成することでしょう。
ですので、

```
rake sitemap:refresh:no_ping
```
で作成した後、

```bash
cat tmp/sitemap.xml.gz | xmllint --format --encode utf-8 - | less
```
で確認するという感じで使用しています。

## [appraisal](https://github.com/thoughtbot/appraisal)
 - 主にgemを作るときに用いるgemです。
 - gemを作る際、依存するgemの様々なバージョンに対応しないといけません。そのときにテストを楽にしてくれるのが、appraisalです。
 - 使い方はAppraisalsファイルに次の様に記載します。（READMEから拝借）例では、rails-3とrails-4の最新のバージョンでテストしたい場合になります。

```ruby
appraise "rails-3" do
  gem "rails", "~> 3.2.0"
end

appraise "rails-4" do
  gem "rails", "~> 4.2.0"
end
```
 - その後、`bundle exec appraisal install`コマンドを打つと、gemfilesというディレクトリができ、その中にrails-3.gemfileやrails-4.gemfileが追加されます。
 - 全てのバージョンでのテストをしたいときは、次の様なコマンドが用意されています。

```bash
bundle exec appraisal rake test  # minitestの場合
bundle exec appraisal rspec spec # rspecの場合
```
 - 特定のバージョンをテストしたいときは次の様になります。

```bash
bundle exec appraisal rails-3 rake test  # minitestの場合
bundle exec appraisal rails-3 rspec spec # rspecの場合
```

# そのほかコメント
 - [ancestry](https://github.com/stefankroes/ancestry)
    - リレーショナルデータベースで木構造を取り扱う場合の`系列列挙モデル`で実装したgem。系列列挙モデルの場合、pathの整合性が取れなくなる可能性がある懸念から、抵抗があります。自分で隣接リストモデルで実装してしまうことが多いです。[^2]
 - [annotate](https://github.com/ctran/annotate_models)
    - データベスを見に行けばわかる情報わざわざモデル内に書き込むのは如何なものかと思いました。
 - [better_errors](https://github.com/charliesome/better_errors)
    - Rails5系から、`puma`が利用されることになり、相性の問題からか重くなっているようです。解決する方法も報告されていますが[^3]、`binding.pry`などでデバッグできるので、あまり必要性を感じなくなりました。 
 - [bullet](https://github.com/flyerhzm/bullet)
    - N+1を教えてくれるgemですが、個人的にはコード書いてる時やログ見ているときに気づくのではと思いました。とはいえ、見逃す時もあるので、嬉しいときもあります。
 - [dotenv-rails](https://github.com/bkeepers/dotenv) 
    - 開発時には[direnv]()を使えばいいかなと思います。本番環境でも、デプロイ時などにうまく環境ごとにセットできる方法があるはず。AWSのElasticBeanstalkでは簡単にセットできます。
 - [ransack](https://github.com/activerecord-hackery/ransack)
    -  コード的にはシンプルだが重いSQLを生み出し、大幅に速度低下していたのを生SQLで書き直した経験があり、ransackでできることぐらいであれば自分でActiveRecord経由でSQL構築した方がいいと思う派です。

# 最後に
gem良いですよね。

[^2]: [Railsでツリー構造（階層構造）をもったカテゴリを隣接リストモデルで実装する](https://qiita.com/yuyasat/items/1200d7a6b56bae0c6f57)
[^3]: [Rails 5.0 + Puma 3系の環境でBetter Errors + binding_of_caller が遅い](http://y-yagi.tumblr.com/post/144335019925/rails-50-puma-3%E7%B3%BB%E3%81%AE%E7%92%B0%E5%A2%83%E3%81%A7better-errors)