Railsやるなら知っておきたい便利Gem


([リクルートライフスタイル Advent Calendar 2015 - Qiita](http://qiita.com/advent-calendar/2015/recruitlifestyle) の18日目)


@MomokoAsai です。ショプリエを担当してます。サーバーサイドエンジニアです。


業務でも個人でもRails4.2を使っておりまして
『今ってどのgemが良さ気なの？』を改めて調べてみたので、紹介したいと思います。

今まで使ってたgemが ”Rails4から標準モジュールに統合されているからいらない” とか ”開発がもう止まってる”
とかもあったので、参考にしていただければと。
ちょっとした`例`も、載せているものは載せているので、参考にしていただければと。


||
|:-----------|
|2015/12/18 現在|


# Gem の紹介 


## ■ デスクトップ/スマートフォン のテンプレート出し分け

- [jpmobile](https://github.com/jpmobile/jpmobile)  => を、やめた <br>
   →　Rails4.1から標準機能で、variant が追加されたので、そっちを採用

~~いきなりgemじゃないけれど~~

`例) `
スマートフォン出し分け関数を作り
※ Rails4からは、`controller`, `model`以下に`concerns`ディレクトリが出来たので、そちらに。`concern`については割愛

```rb:app/controllers/concerns/user_agent.rb
module UserAgent
  extend ActiveSupport::Concern

  def is_mobile?
    request.user_agent =~ /iPhone|iPad|Android/
  end
end
```
スマートフォンなら`:smart` に振り分けられるように書く

```rb:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include UserAgent

  protect_from_forgery with: :exception

  before_action :detect_device_variant
  private
  def detect_device_variant
    request.variant = :smart if is_mobile?
  end
end
```
こうすると、参照するテンプレートを設定した形式で分けてくれます。
＃今回は「smart」で出し分け

```bash
app/views/show.html+smart.erb
app/views/show.html.erb
```

## ■ 画像アップロード機能

- [refile](https://github.com/refile/refile)
- [carrierwave](https://github.com/carrierwaveuploader/carrierwave)


`refile` は `carrierwave`の作者が作った後継 gemです。
`carrierwave`に欲しかった機能が盛り込まれています。

- s3へのブラウザから直接アップロードのサポート
- サムネイルの動的生成サポート

などなど
`carrierwave`と同じ作者ということもあり、これは安心かつ嬉しいですね。
日本語の情報はまだまだ少ないです。

 
他の画像アップロードのgemは有名ドコロとして `carrierwave`と`paperclip`があります。
それぞれ簡単に比較するとこんな感じ。

|gem|こんな人 |特徴|
|:------------:|:------------:|:------------:|
|CarrierWave|凝ったことをやりたい|多機能、柔軟性の高い|
|Paperclip|シンプルな機能を手早く実装したい|シンプル|

参考：http://blog.inouetakuya.info/entry/20131014/1381749488



## ■ ABテスト
- [split](https://github.com/splitrb/split)

前にいたチーム([ギャザリー](http://gathery.recruit-lifestyle.co.jp/))で、
このgemを使ってABテストを行っていました。大変お世話になったgemさんです。

これを使うと、ユーザーSession毎に表示や処理の出し分けが出来るようになります。
さらに、「何%をAパターンに割り当てるか？」の指定も簡単に出来てしまいます。

`Split uses redis as a datastore.`
READMEにもある通り、redisを使ってこれらを実現してるので、redisを用意しましょう。


`例）`
基本、下の2つメソッドで事足ります。
`finished`は、コンバージョン達成を特に設けない場合は必要ないです。

| メソッド　　 |内容　　|
|:------------:|:-----------|
| ab_test       |ABテストの開始時に呼び出す (ユーザー振り分け＆Session関連をRedisに保存) |
| finished       |コンバージョン達成時に呼び出す (Session関連をリセット)|

では、いきます。
画像出しわけだけであれば、これだけで完了です。

```erb
<% ab_test(:login_button, "/images/button1.jpg", "/images/button2.jpg") do |button_file| %>
  <%= image_tag(button_file, alt: "Login!") %>
<% end %>
```
もう少しいろいろやりたい・何種類もやりたい場合は、
設定ファイルを用意して、出し分け毎にif文などでくくってしまうと、いろいろ出来ます。

```rb
Split.configure do |config|
  config.experiments = YAML.load_file "config/experiments.yml"
end
```
```yaml:config/experiments.yml
my_first_experiment:
  alternatives:
    - A
    - B
my_second_experiment:
  alternatives:
    - name: A
      percent: 60
    - name: B
      percent: 40
```
```rb
abtest_second = ab_test(:my_second_experiment)
...

if abtest_second == 'A' 
  # 処理させたい内容を記載
end
```
これで、60%の人がAパターンになる出し分けが出来ます。

`finished`を設定して、コンバージョンレートなどが見れるDashboardもあります。



## ■ ユーザー権限

- [pundit](https://github.com/elabs/pundit)


`cancan`(進化系`cancancan`)が有名ドコロとしてありましたが、
開発が止まってしまっているのと、`Pundit`のほうが柔軟性が高いので、こちらを。

認可ルールの記載場所は、一つのファイルにまとめるのではなく
コントローラ毎・リソース毎のように、柔軟に作成できます。
generateタスクも用意されています。

`例）`

```rb:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include Pundit      # <= インクルードしておく

  protect_from_forgery
end
```
Punditにはauthorizeというメソッドが用意されており、

````rb:app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :pundit_auth

  ...

  private
    def pundit_auth
      authorize User.new
    end
```
```rb:app/model/user.rb
class User < ActiveRecord::Base
    def self.admin?
    ...
    end
end
```
````rb:app/policies/user_policy.rb
class UserPolicy < ApplicationPolicy
  def update?
    user.admin?
  end
...
```
これで`UsersController#update`が実行された際に`current_user.admin`が
`false`だった際、`NotAuthorizedError`という例外が発生します。


参考：http://magazine.rubyist.net/?0047-IntroductionToPundit


比較として参考までに、
シェアはまだ`cancan`のほうが高いですが、今後は`pundit`の方が伸びそうですね。
![rails_authorization.png](https://qiita-image-store.s3.amazonaws.com/0/15055/9b712ee3-1401-d9e6-1d82-b0723114e28d.png)

![cancan_pundit_cancancan.png](https://qiita-image-store.s3.amazonaws.com/0/15055/2e9769b8-5616-9138-23d9-74fb16abd0f0.png)



## ■ メンテナンス
- [turnout](https://github.com/biola/turnout)

メンテナンス画面を簡単に作成出来ます。
Railsのディレクトリに `tmp/maintance.yml` を置くと、設定したメンテナンス画面が表示され、サービスをメンテナンス中に出来てしまいます。
メンテナンス時に除外するIPアドレス、URLの指定も簡単です。

Capistranoとの連携も。
参考：http://morizyun.github.io/blog/turnout-maintenance-rails/


## ■ 検索機能

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

シノニム設定は出来ないですが、お手軽に検索のsqlが組み立てられます。



## ■ デバッグ関連

- [better_errors](https://github.com/charliesome/better_errors)
- [binding_of_caller](https://github.com/banister/binding_of_caller)

王道。便利。
`better_errors`使うなら、`binding_of_caller`も一緒に入れましょう。エラー画面でirbが利用出来るようになります。
pryを起動しているコンソールに戻るのが面倒な方にオススメです。

![better_errors.gif](https://qiita-image-store.s3.amazonaws.com/0/15055/98b970de-8ad8-af32-4adb-5c0173d8f648.gif)


## ■　テスト関連

- [factory_bot_rails](https://github.com/thoughtbot/factory_bot_rails)

Fixtureがありますが、DBにテストデータを入れずに値だけほしい時だって、ありますね。
そんな時に便利です。


## ■ UserAgentごにょごにょ
- [woothee](https://github.com/woothee/woothee)

ユーザーエージェントから、OSとブラウザ名、バージョンなどを取り出せるため、
ログとかで結構活躍します。

`例)`

```rb
Woothee.parse("Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)")
# => {:name=>"Internet Explorer", :category=>:pc, :os=>"Windows 7", :version=>"8.0", :vendor=>"Microsoft", :os_version=>"NT 6.1"}
```


## ■ プレゼンテーション層追加
- [draper](https://github.com/drapergem/draper)

Draperは、Railsのプレゼンテーション層の役割を担うgemです。
可読性、保守性を向上できます。

- ビューにif文が多くて見づらい
- ビューのロジックをヘルパーに書いているがヘルパーの名前空間の衝突が怖い

な人にオススメです。


参考：http://morizyun.github.io/blog/draper-ruby-gem-code-clear/

## ■ 攻撃対応
- [rack-attack](https://github.com/kickstarter/rack-attack)

世の中は脅威に満ちています。
これを使えば、特定のパスへのアクセスを簡単に制限できます。

`例)` by github

```rb
# Always allow requests from localhost
# (blacklist & throttles are skipped)
Rack::Attack.whitelist('allow from localhost') do |req|
  # Requests are allowed if the return value is truthy
  '127.0.0.1' == req.ip || '::1' == req.ip
end
```
```rb
Rack::Attack.blacklist('only allow from office') do |req|
  req.path.match(%r{^/admin}) && (req.ip != OFFICE_IP_ADDRESS)
end
```
```rb
# Throttle login attempts for a given email parameter to 6 reqs/minute
# Return the email as a discriminator on POST /login requests
Rack::Attack.throttle('logins/email', :limit => 6, :period => 60.seconds) do |req|
  req.params['email'] if req.path == '/login' && req.post?
end
```



# gem 探しツール




## Ruby Toolbox

皆さんご存知
https://www.ruby-toolbox.com/


## Github Trending repositories

https://github.com/trending?l=ruby

gem only ではないですが、指標のひとつとして。

## BestGems
http://bestgems.org/

ダウンロード数を集計してRankingで表示してくれます。
toolboxと違って、Dailyとかでも見れるので、最近急に人気になったgemを見つけられそうです。
　http://bestgems.org/featured
　

## 有名どころの Gemfile

https://github.com/gitlabhq/gitlabhq/blob/master/Gemfile

　
　
　
　
　
　

該当gemの開発頻度(最終commit日時とか)や、世の中のgemトレンドを見ながら、
快適な gem Lifeを ♡