Railsでサーバ立ち上げのときのみ実行するコードの配置 - Initialization Codes Executed Only in Server Mode (Rails)

# TL;DR

`config.ru` の `run Rails.application` Statement の直前に書く。

```ruby
# This file is used by Rack-based servers to start the application.

require_relative 'config/environment'

p "Initialization codes should come here."
p "In config.ru file, #{Rails.env}, models can also be handled #{Article.name}"
run Rails.application
```

# 経緯

rails で HTTP アプリケーションを立ち上げつつ、同時に `discordrb` gem を使って discord bot も立ち上げたかった。
## 要件
1. RailsでHTTPアプリのServe
2. RailsのHTTPアプリで利用するModelやJobをdiscordrbボットでも流用する
3. `rails s`コマンドや`rails unicorn:start`コマンドの実行時に自動的にdiscord bot立ち上げる
4. `rails c`コマンドやrails task起動時にはdiscord botが立ち上がってほしくない（重複するため）

初めは `config/initializers/discord.rb` にbot起動コードを書いていたが、これだと要件4が満たされない
かといって、単独のrubyプログラムとしてdiscord botを記述してしまうと、要件2が満たされない
さらに、下手くそなので`rails s`時に自動的にbotが立ち上がらないと、忘れてしまう。（要件3）

## ネット上で散見される解決策
1. Rails::Server#initialize をオーバーライドしろ
2. Rails::Server定数の定義の有無をチェックしてif分岐しろ

    ```ruby
if defined?(Rails::Server)
  # do something
end
```

しかし、1. は、ブラックボックス触りたくない
2. はRackハンドラ (e.g. unicorn, WEBrickなど) が変わると通用しない

ので、他の方法を模索しました。

## （いきなり）解決策
`config.ru` に書け。
これはrails appが読み込まれ、initializersの処理等も終わったタイミングで呼び出される。
しかも、`rails c`など実行時には呼ばれない。

### 実験
#### 準備
1. `rails new hoge` で空のRails app作成
2. `rails g model Article title:string content:text published_at:datetime` でそれっぽく作る
3. `rails g job ArticlePublishJob` でそれっぽく（対照実験用）
4. rails taskもそれっぽく作る
5. config/initializers/sample.rbもそれっぽく
6. 肝の部分はconfig.ru
7. `rails db:migrate` して準備完了

  ```ruby
# app/job/article_publish_job.rb

class ArticlePublishJobJob < ApplicationJob
  queue_as :default

  def perform(article)
    article.update(published_at: Time.zone.now)
  end
end
```

  ```ruby
# lib/tasks/articles.rake
namespace :articles do
  desc "publish all articles"
  task :publish => :environment do
    Article.all.each do |article|
      ArticlePublishJob.perform_later article
    end
  end
end
```

  ```ruby
# config/initializer/sample.rb
p "In config/initializers/sample.rb file, #{Rails.env}, #{Article.name}"
Article.create(title: "Sample article", content: "This is a sample article...")
```


  ```ruby
# config.ru

# This file is used by Rack-based servers to start the application.

require_relative 'config/environment'

p "Initialization codes should come here."
p "In config.ru file, #{Rails.env}, models can also be handled #{Article.name}"
run Rails.application
```
#### いざ、試験

##### まず, `rails s`

  ```
/tmp/hoge% rails s
=> Booting Puma
=> Rails 5.0.7 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
"In config/initializers/sample.rb file, development, Article"
"Initialization codes should come here."
"In config.ru file, development, models can also be handled Article"
Puma starting in single mode...
* Version 3.11.4 (ruby 2.5.1-p57), codename: Love Song
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2018-05-28 19:03:26 +0900 ===
- Goodbye!
Exiting
```
ちゃんとconfig.ru内のコードが実行されている

##### 次は`rails c`

  ```
/tmp/hoge% rails c
Running via Spring preloader in process 16334
Loading development environment (Rails 5.0.7)
irb(main):001:0> Article.last
  Article Load (0.6ms)  SELECT  "articles".* FROM "articles" ORDER BY "articles"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> #<Article id: 1, title: "Sample article", content: "This is a sample article...", published_at: nil, created_at: "2018-05-28 10:12:06", updated_at: "2018-05-28 10:12:06">
irb(main):002:0>
```

`config/initializers/*` なファイルだけ実行される。
想定通り。

##### さいごに `rails articles:publish`

  ```
/tmp/hoge% rails articles:publish
"In config/initializers/sample.rb file, development, Article"
```
これもOK

## さいごに
いろいろ調べたけど, config.ru はRackのエントリーポイントっぽく、RackはHTTPアプリケーションフレームワークということで、HTTP鯖upするときだけ呼ばれるという挙動は納得です。
今回の実装がベクとプラクティスかどうかはわかりませんが、いろいろググってもしっくり来る実装がなくてこの対処に落ち着きました。
他にこんな良い方法あるよ！っていうのがあれば教えて頂けると幸いです。

Rackアプリケーションの概要については @higuma さんの下記記事が大局観をつかみやすく、わかりやすかったです。ありがとうございました。
[Rack解説 - Rackの構造とRack DSL](https://qiita.com/higuma/items/838f4f58bc4a0645950a)