Railsで痒い所に手が届くTips8選【脱初心者】

PythonとかPHPと触ってた僕が、自力でRailsチュートリアルをやり始めたが挫折。
そんな僕が社内研修（座学）でRailsを使えるようになりました。
その後の実習にてアプリケーションを作った時に、「もっと早く知っていれば」「そんな技があるのか・・・」と思ったTipsです。
Rails本体だけでなく、gemにも触れます。

## 目次
- Rails Model 編
  - [arel_table](#arel_table)
  - [scope](#scope)
- Rails ルーティング 編
  - [resourcesの入れ子](#resourcesの入れ子)
- gem 編
  - [pry-byebug](#pry-byebug)
  - [hirb](#hirb)
  - [erd](#erd)
- 自動化編
  - [itamae](#itamae)
  - [Capistrano](#Capistrano)
- [参考リンク集](#参考リンク集)

## Rails Model 編
こんな感じの状況で説明します

```ruby:schema.rb
ActiveRecord::Schema.define(version: 20160725113659) do
  create_table "users", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at",                null: false
    t.datetime "updated_at",                null: false
    t.boolean  "is_man",     default: true
  end
end

```

```ruby:UserModel
class User < ActiveRecord::Base
  has_many :tweets
  scope :men, -> { where(is_man: true) }
  scope :women, -> { where(is_man: false) }
 end
```

```ruby:TweetModel
class Tweet < ActiveRecord::Base
  belongs_to :user

  # Userモデルをjoin
  scope :with_user, -> { includes(:user).references(:users) }
  # 男性によるツイート
  #scope :by_men, -> { with_user.where(User.arel_table[:is_man].eq(true)) } # 追記: 非推奨
  scope :by_men, -> { joins(:user).merge(User.men) }
end
```

```ruby
[13] pry(main)> User.all
  User Load (0.2ms)  SELECT "users".* FROM "users"
=> [#<User:0x007fc9c9dde948 id: 1, name: "山田花子", is_man: false>,
 #<User:0x007fc9c9dde628 id: 2, name: "鈴木太郎", is_man: true>,
 #<User:0x007fc9c9dde2b8 id: 3, name: "伊藤二郎", is_man: true>]
[14] pry(main)> Tweet.all
  Tweet Load (0.1ms)  SELECT "tweets".* FROM "tweets"
=> [#<Tweet:0x007fc9cb0712e0 id: 1, containts: "{:containts=>\"ツイートは140文字まで\"}", user_id: 1>,
 #<Tweet:0x007fc9cb070c00 id: 2, containts: "{:containts=>\"実際は違うけどね\"}", user_id: 2>]
```

### scope
SQLのクエリのエイリアス的なやつです。
共通で使うクエリをモデルのstaticなメソッドのように使え、メソッドチェーンも使えるので直感的に複雑なクエリをつくれます。

Userモデルに定義したこの2つのscope
"ユーザで`is_man`が`true`"
`scope :men, -> { where(is_man: true) }`
"ユーザで`is_man`が`false`"
`scope :women, -> { where(is_man: false) }`

実際にはこんな感じ

```ruby
[1] pry(main)> User.men
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."is_man" = ?  [["is_man", "t"]]
=> [#<User:0x007fc9cd2039d0 id: 2, name: "鈴木太郎", is_man: true>,
 #<User:0x007fc9cd200208 id: 3, name: "伊藤二郎", is_man: true>]
[2] pry(main)> User.women
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."is_man" = ?  [["is_man", "f"]]
=> [#<User:0x007fc9cd0638f0 id: 1, name: "山田花子", is_man: false>]
```

scopeの`{}`中の条件でUserモデルに対してクエリを実行できます。
さらに、メソッドチェーンもできます。例は次項にて。

### arel_table
Modelに対してちょっと込み入ったSQLクエリを投げたい時に便利です。

"男性のツイート一覧"をこう書けます。
`  scope :by_men, -> { with_user.where(User.arel_table[:is_man].eq(true)) }`
このように、
- where句に対して別テーブルのキーを指定したい時（`.where(User.arel_table[:is_man].eq(true))`）
- カラム指定で文字列を使いたくない時（`User.arel_table[:is_man].eq(true)`）

```
[6] pry(main)> Tweet.by_men
  SQL (0.2ms)  SELECT "tweets"."id" AS t0_r0, "tweets"."containts" AS t0_r1, "tweets"."user_id" AS t0_r2, "tweets"."created_at" AS t0_r3, "tweets"."updated_at" AS t0_r4, "users"."id" AS t1_r0, "users"."name" AS t1_r1, "users"."created_at" AS t1_r2, "users"."updated_at" AS t1_r3, "users"."is_man" AS t1_r4 FROM "tweets" LEFT OUTER JOIN "users" ON "users"."id" = "tweets"."user_id" WHERE "users"."is_man" = 't'
=> [#<Tweet:0x007fc9c9f34fb8 id: 2, containts: "{:containts=>\"実際は違うけどね\"}", user_id: 2>]
```

上の例は何気にメソッドチェーンをしていて、
自分で定義した`with_user`メソッドに`where`メソッドをつなげて書いています。
このように、scopeをうまく使うと複雑なメソッドを直感的に書くことができます。
ただし、使いすぎるとよくわからなくなるので注意です。

### 追記
`arel_table` についてコメントでご指摘いただきました
https://qiita.com/tkhr/items/9b79bce27f20191eb78f#comment-637a5f85bae3d8d6f3fa

`arel_table` は ActiveRecord 標準のクエリインターフェースではないので使用するのは推奨されない、とのことでした

> `scope :by_men, -> { with_user.where(User.arel_table[:is_man].eq(true)) }`

は

> `scope :by_men, -> { joins(:user).merge(User.men) }`

のように、 `joins` と `merge` を組み合わせて書くことができます

`Usre.men` を条件として組み合わせたいので、
`joins(:user)` で UserModel と `join` して、
`merge` を使うことで `User.men` の条件を追加します

ご指摘ありがとうございました
遅くなってしまいましたが、追記させていただきました :bow:

## Rails ルーティング 編
### resourcesの入れ子
ユーザとそのツイートを表す時。


```ruby:routes.rb
  resources :tweets
  resources :users
```

![スクリーンショット 2016-07-26 9.54.54.png](https://qiita-image-store.s3.amazonaws.com/0/7442/69d050cb-a5ce-8f23-d3af-c06ae88d6015.png "スクリーンショット 2016-07-26 9.54.54.png")

このようにしちゃうとうまく扱えない。

ユーザとツイートには包含関係があるので、resourcesも入れ子にする。

```ruby:routes.rb
  resources :users do
    resources :tweets
  end
```
![スクリーンショット_2016-07-26_9_55_47.png](https://qiita-image-store.s3.amazonaws.com/0/7442/46b4f5ed-4133-b3b1-a420-9e362fd9f951.png "スクリーンショット_2016-07-26_9_55_47.png")

こうすると

- `/users/1/tweets`でユーザID1のツイート一覧
- `/users/2/tweets/30`でユーザID2でツイートID30のツイート

みたいに扱える。

ちなみに、resourcesだけでなく、get,postなども入れ子にできる。

```ruby:routes.rb
  resources :users do
    get :tweets, to: 'tweets#index'
    post :follow, to: 'users#follow'
  end
```

![スクリーンショット_2016-07-26_10_09_50.png](https://qiita-image-store.s3.amazonaws.com/0/7442/16dc408e-aa1d-83ec-9b79-546b36ea2a31.png "スクリーンショット_2016-07-26_10_09_50.png")


## gem 編
ここで紹介するものはGemfileに次のように書けば:+1:

```ruby:Gemfile
group :development do
  gem 'pry-byebug'   # pry-byebug
  gem 'pry-rails'    # pry
  gem 'hirb'         # hirb
  gem 'hirb-unicode' # hirb
  gem 'rails-erd'    # erd
end
```

### pry-byebug
railsで使えるデバッガで、ブレークポイントの設定やステップ実行ができます。
アプリを動かして好きなタイミングで動作を一時停止して変数の中身を見たり、
1行づつ順に実行して変数の値を追うことができます。
つまり、いろんなところに`p`を置いて変数の中身を確認するプリントデバッグとはおさらばです。

使い方は
29行目のように、処理を中断したいところに`binding.pry`と1行いれるだけです。
![スクリーンショット 2016-07-24 22.10.00.png](https://qiita-image-store.s3.amazonaws.com/0/7442/62cabd25-dfea-3c5c-d911-8092fda18a5a.png "スクリーンショット 2016-07-24 22.10.00.png")

とやると、サーバの処理が一時停止してコンソールが立ち上がります。
ここで変数を見たり、DBを確認したり、だいたい全部できます。
![スクリーンショット 2016-07-24 22.08.41.png](https://qiita-image-store.s3.amazonaws.com/0/7442/373f274e-f8d7-6947-cbf0-05baa1163ecd.png "スクリーンショット 2016-07-24 22.08.41.png")

便利！


詳しくはこちら：http://blog.toshimaru.net/rails-pry-byebug/
リポジトリ：https://github.com/deivid-rodriguez/pry-byebug

### pry
pryはirbのリッチなやつです。
irbよりも多機能かつ色付きなのではかどります。
ドキュメントを見れたり、riコマンドが使えます。
また、タブキーによる補完があります。
ソースの表示が上の画像みたいにカラーに。

多機能すぎるのでもっと詳しい人の参考：[今更聞けないpryの使い方と便利プラグイン集 - Qiita](http://qiita.com/k0kubun/items/b118e9ccaef8707c4d9f#pry%E6%A8%99%E6%BA%96%E3%81%AE%E6%A9%9F%E8%83%BD)

### hirb
Modelの出力を表形式にしてくれます。
なので直感的に結果を理解できます。

こんな感じ。
![スクリーンショット 2016-07-25 21.30.09.png](https://qiita-image-store.s3.amazonaws.com/0/7442/d11d0324-fe8a-531e-fe69-08518f64a972.png "スクリーンショット 2016-07-25 21.30.09.png")

#### 使い方
コンソールで`Hirb.enable`と入力します。

#### インストール  

```ruby:Gemfile
gem 'hirb'
gem 'hirb-unicode' # 日本語を扱う場合には必要
```
pryと併用する場合にはひと手間加えます。
Railsのルートディレクトリ（Gemfileがある場所）に次のファイルを作成します。

```ruby:.pryrc
# .pryrc
begin
  require 'hirb'
rescue LoadError
  # Missing goodies, bummer
end

if defined? Hirb
  # Slightly dirty hack to fully support in-session Hirb.disable/enable toggling
  Hirb::View.instance_eval do
    def enable_output_method
      @output_method = true
      @old_print = Pry.config.print
      Pry.config.print = proc do |*args|
        Hirb::View.view_or_page_output(args[1]) || @old_print.call(*args)
      end
    end

    def disable_output_method
      Pry.config.print = @old_print
      @output_method = nil
    end
  end

  Hirb.enable
end
```

- リポジトリ：[cldwalker/hirb](https://github.com/cldwalker/hirb)

### erd
プロジェクトのModelの定義やschema（とかその辺）からDBをER図にしてくれます。
pdfやpngなど出力形式やカラムの指定も結構自由にできるみたいです。

![erd.png](https://qiita-image-store.s3.amazonaws.com/0/7442/fa120e44-306d-30d5-e9a9-6628fb9c8f6f.png "erd.png")
[voormedia/rails-erd](https://github.com/voormedia/rails-erd)より


#### インストール  
外部モジュールを使っているので、インストールの時に以下が必要です。

```bash
brew install graphviz
```

#### 使い方
プロジェクトのルートディレクトリにPDF形式で出力されます。

```ruby
bundle exec erd
```

いろいろオプションがあるので
詳しくはこちら：[Rails ERDの導入と実行](http://qiita.com/kanpou_/items/74eca1846101e6db3387)
リポジトリ：[voormedia/rails-erd](https://github.com/voormedia/rails-erd)

## 自動化編

### itamae
サーバ環境をコードで管理して、自動で構築してくれるツールです。
解説記事を読むと「Chef」という単語が目に付きますが、itamaeはChefのラッパー的なツールです。
Chefだといろいろできすぎてしまうので、機能を制限してわかりやすくしてくれたのがitamaeです。

解説記事を読みながら実際のレシピをカスタマイズしていきました。
解説記事は運用の細かいところまで解説してくださっているので、あまりよくわからないところは実際に動かしてみて理解するのも手だと思います。

この記事を参考に
[Chef脱落者が、Itamaeで快適インフラ生活する話 - Qiita](http://qiita.com/zaru/items/8ae6182e544aac6f6d79)
[Chef-soloからItamaeに完全移行した話 - Qiita](http://qiita.com/toritori0318/items/00ea2a75c8321aaf9ef6)
[Itamae + rbenvでCentOSにRuby環境を構築 - Qiita](http://qiita.com/fukuiretu/items/337e6ae15c1f01e93ec3)

これをカスタマイズする
[zaru/itamae-rails](https://github.com/zaru/itamae-rails)

やり方でやりました。

補足：
Infrastracture as Code という考え方があります。
サーバ環境をコードによって管理することで、バージョン管理できて、誰がやっても同じ環境が作れる→Happy！
あと、個人的にはサーバ環境がコードとしてまとまっているというのが嬉しいです。何を入れたかとか忘れちゃうし、環境作ってる間に何入れたのかわからなくなっちゃうし。
詳しくは　[Infrastructure as Code 再考 - Gosuke Miyashita](http://mizzy.org/blog/2016/04/22/1/)



### Capistrano

Capistranoなるデプロイツールというものがあります。こいつは衝撃でした。
開発中はデプロイのことは頭にありませんが、「AWSのEC2で公開してやるぜ！」とかなった時に、途端に負荷が跳ね上がる。
これを勝手によしなにしてくれるというものですね。CIに近づく一歩です。

解説記事はたくさんあります。もちろんQiitaにも。
ですが、記事にはそれぞれに環境の差があるので例を組み合わせるだけではなかなかうまくいきませんでした。
でも、この記事でCapistranoの全貌を大まかに把握してから、例を見ると応用が利くようになり、夢の自動化を達成しました。
[入門 Capistrano 3 ~ 全ての手作業を生まれる前に消し去りたい | GREE Engineers&#039; Blog](http://labs.gree.jp/blog/2013/12/10084/)
あとは、この辺でざっくりした具体例を見る。
[capistrano 3 をできるだけシンプルにサーバーにコマンドを流し込むツールとして使いこなす - Qiita](http://qiita.com/kazuph/items/deeaa7d3f9889674d7fe)

この辺で設定の例を見る。

- [Capistrano で Rails アプリケーションの自動デプロイ - Qiita](http://qiita.com/Salinger/items/4ee4f3c5ebd5227196c0)
- [Capistrano3でUnicorn+Nginxな環境にRailsをデプロイする:初心者向け - Qiita](http://qiita.com/zaru/items/9e02706b27094ce36902)
- [【入門】Capistrano3で自動デプロイ](http://qiita.com/mr-myself/items/2769676e6dcf43db41ef)

## まとめ
結構ボリュームが大きくなってしまいました

## 参考リンク集
- [pry-byebug を使ってRailsアプリをステップ実行する - Hack Your Design!](http://blog.toshimaru.net/rails-pry-byebug/)
- [deivid-rodriguez/pry-byebug](https://github.com/deivid-rodriguez/pry-byebug)
- [今更聞けないpryの使い方と便利プラグイン集 - Qiita](http://qiita.com/k0kubun/items/b118e9ccaef8707c4d9f)
- [cldwalker/hirb](https://github.com/cldwalker/hirb)
- [voormedia/rails-erd](https://github.com/voormedia/rails-erd)
- [Rails ERDの導入と実行](http://qiita.com/kanpou_/items/74eca1846101e6db3387)
- [Chef脱落者が、Itamaeで快適インフラ生活する話 - Qiita](http://qiita.com/zaru/items/8ae6182e544aac6f6d79)
- [Chef-soloからItamaeに完全移行した話 - Qiita](http://qiita.com/toritori0318/items/00ea2a75c8321aaf9ef6)
- [Itamae + rbenvでCentOSにRuby環境を構築 - Qiita](http://qiita.com/fukuiretu/items/337e6ae15c1f01e93ec3)
- [zaru/itamae-rails](https://github.com/zaru/itamae-rails)
- [Infrastructure as Code 再考 - Gosuke Miyashita](http://mizzy.org/blog/2016/04/22/1/)
- [入門 Capistrano 3 ~ 全ての手作業を生まれる前に消し去りたい | GREE Engineers' Blog](http://labs.gree.jp/blog/2013/12/10084/)
- [capistrano 3 をできるだけシンプルにサーバーにコマンドを流し込むツールとして使いこなす - Qiita](http://qiita.com/kazuph/items/deeaa7d3f9889674d7fe)
- [Capistrano で Rails アプリケーションの自動デプロイ - Qiita](http://qiita.com/Salinger/items/4ee4f3c5ebd5227196c0)
- [Capistrano3でUnicorn+Nginxな環境にRailsをデプロイする:初心者向け - Qiita](http://qiita.com/zaru/items/9e02706b27094ce36902)
- [【入門】Capistrano3で自動デプロイ](http://qiita.com/mr-myself/items/2769676e6dcf43db41ef)