Herokuのスラグサイズを減らすためにasset_syncを使うやりかた


[Denkinovel](http://denkinovel.com/)という、ノベルゲーム風の小説を書ける投稿サイトをRails + Herokuで開発しています。

サービスの特性上assetsに多くの画像、音楽ファイルを置いているので、Herokuの[Slug size 200MB縛り](https://devcenter.heroku.com/articles/slug-compiler)がきつくなってきました。こんな状況のために[asset_sync](https://github.com/rumblelabs/asset_sync
)というgemがあるので、使ってみることにしました。Heroku公式で推奨しているgemです。

herokuでのasset_syncの使い方は、英語公式がこちら。https://devcenter.heroku.com/articles/cdn-asset-host-rails31

ボランティアによる日本語訳もあります。ありがたい。こちらです。https://github.com/herokaijp/devcenter/wiki/cdn-asset-host-rails31


## インストール

heroku公式の解説に従って

```Gemfile
gem "asset_sync"
```

をGemfileに書いて

```
$ bundle
```

します。
このあとも解説のとおりにherokuの環境変数を設定します。

```
$ heroku config:add FOG_PROVIDER=AWS
$ heroku config:add AWS_ACCESS_KEY_ID=xxx
$ heroku config:add AWS_SECRET_ACCESS_KEY=yyy
$ heroku config:add FOG_DIRECTORY=yourappname-assets
```

でherokuの環境変数を追加。
このあと、
config/environments/production.rb内の設定もコメントアウトを外して設定を追加。

```ruby:config/environments/production.rb
config.action_controller.asset_host = "https://#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com"
```

とします。

## asset_syncの設定変更
S3を日本のリージョンで使っている場合は、asset_syncの設定を変える必要があります。

https://github.com/rumblelabs/asset_sync

を参考に、

```
$ rails g asset_sync:install --provider=AWS
```


します。これで/config/initializer/asset_sync.rb が誕生するので、設定を書き加えましょう。

東京リージョンなので、デフォルトのus-east-1ではなく

```ruby:/config/initializer/asset_sync.rb
config.fog_region = 'ap-northeast-1'
```
に修正します。


https://github.com/rumblelabs/asset_sync/issues/125

で推奨されているように、

/config/initializer/asset_sync.rb

では、

```ruby:/config/initializer/asset_sync.rb
if defined?(AssetSync)
  AssetSync.configure do |config|
    config.fog_provider = 'AWS'
    config.aws_access_key_id = ENV['AWS_ACCESS_KEY_ID']
    config.aws_secret_access_key = ENV['AWS_SECRET_ACCESS_KEY']
    config.fog_directory = ENV['FOG_DIRECTORY']

    # Increase upload performance by configuring your region
    config.fog_region = 'ap-northeast-1'
    #
    # Don't delete files from the store
    # config.existing_remote_files = "keep"
    #
    # Automatically replace files with their equivalent gzip compressed version
    # config.gzip_compression = true
    #
    # Use the Rails generated 'manifest.yml' file to produce the list of files to 
    # upload instead of searching the assets directory.
    # config.manifest = true
    #
    # Fail silently.  Useful for environments such as Heroku
    # config.fail_silently = true
  end
end
```

というように、

```
if defined?(AssetSync)
...
end
```
で囲みます。囲まないでデプロイしたあと、ウェブサイトにアクセスすると**uninitialized constant AssetSync (NameError)**なるエラーが発生しました。注意。

## プリコンパイル
asset_syncの設定が完了したら、ローカル環境でプリコンパイルします。assetsのサイズが小さければ、ローカルでのプリコンパイルは必要ないのですが、僕が開発している[Denkinovel](http://denkinovel.com/)の場合、サービスの特性上assetsの容量が大きくならざるをえません。

slug sizeが100MBを越えていたので、プリコンパイルしないでgit push heroku masterするとheroku側でのコンパイルに異様に時間がかかり、time outしてしまいました。なのであらかじめローカルでプリコンパイルしました。

僕はzshを使っているので、.zshenvに

```.zshenv
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=yyy
export FOG_DIRECTORY=yourapp-dev-assets
```
と設定を書き加え、zshを再起動する。

そして

```
$ rake assets:precompile
```
すると、ローカルの/public/assets内にassetsが入ると同時にS3にもプリコンパイルされたassetsファイルがアップロードされます。

## .slugignoreを作る
assetsはS3にアップロードできました。しかし、まだこのままではslug sizeは減りません。

[Heroku公式ドキュメント](https://devcenter.heroku.com/articles/slug-compiler)を参考に、.slugignoreを作りましょう。.slugignoreは名前のとおり、Heroku上でslugを作る際、指定したファイルを無視してslugを構築してくれます。

```.slugignore
/spec
/app/assets
*.jpg
*.png
*.mp3
*.ogg
```
僕は.slugignoreをこう書いて、プロジェクトディレクトリの一番上（.gitignoreがあるのと同じ場所）に置きました。

```.slugignore
/spec
/app/assets
```
だけでいいと思ったんですが、そう書いても.jpgや.mp3を無視してくれませんでした。


## デプロイ
.slugignoreができたらとうとうデプロイです。

```
$ git add . -A
$ git commit -m プリコンパイルした
```
で変更をcommmitしたら、herokuにpushします。

```
$ git push heroku master
```

で、デプロイ完了です。

slug sizeが大幅に小さくなっていることを確認してください。[Denkinovel](http://denkinovel.com/)の場合、140MB以上あったのが18MBになりました。

slug size縛りがこうしてなくると、VPSに移行する動機が弱くなってきますね……そのうち移行しようとは思っているのですが、ユーザーが少ないうちはこれで問題なさそうです。