Edited at

Railsでinitializersに書いた内容をdevelopmentモードで再読み込みさせる

More than 5 years have passed since last update.


外部APIに接続するようなクラスの設計

Railsで外部のAPIサービスにつなぐクラスなどを書く際に、将来的にGemにすることを見越してできる限りそのプロジェクト自体に依存しないように設計すると思います。(ここでいう、「依存しない」とは、たとえばそのプロジェクトのSettingsLogicをこのクラスから見に行かないなど。)

ここで、外部のAPIが接続時にAPIキーと、トランザクション毎に変わる情報を渡さないといけないとすると、APIキーは一度Railsを立ち上げると変わらないのでクラスに持たせて、トランザクションは引数で渡す、ということをやると思います。


lib/external_service_adapter.rb

class ExternalServiceAdapter

include ActiveSupport::Configurable
config_accessor :api_key

def create_transaction(transaction_info)
do_something(self.api_key, transaction_info)
end

private

def do_something(api_key, transaction_info)
puts "api_key: #{api_key}"
puts "transaction: #{transaction_info}"
end
end


では ExternalServiceAdapter.api_key はどこで埋めるかというと、Railsには config/initializers という起動時に読み込まれるものがあるので、そこで以下のように書きます。


config/initializers/initialize_adapter.rb

ExternalServiceAdapter.configure do |config|

config.api_key = 'my_api_key'
end

こうすることで、起動時にAPIキーを渡すことができて問題なく動くし、Gemも自プロジェクトに依存するようなロジックが入らないのでGem公開に近づいて夢が広がります。


だがうまく動かない。現実は厳しい。

ところが、development環境でこの外部接続クラスを編集しながら開発しているとExternalServiceAdapter.api_keyが消えるという事象に遭遇します。


初回

こういうcontrollerを追加

class NanikaController < ApplicationController

def index
ex = ExternalServiceAdapter.new
ex.create_transaction("a")
end
end

※ あくまでサンプルで、controllerから外部接続API直接呼ぶのはおおむね良くないケースが多いので注意

実行 =>

api_key: my_api_key

transaction: a


ExternalServiceAdapterに #do_another というメソッドを追加する


lib/external_service_adapter.rb

   def create_transaction(transaction_info)

do_something(self.api_key, transaction_info)
+ do_another
end

---
+ def do_another
+ puts 1
+ end


この後に再び先ほどのcontrollerを実行

=>

api_key:

transaction: a
1


なぜ消えるのか

理由は明快で、developmentモードでソースを編集すると、Railsがリロードしてくれます。便利。

ただしinitializersの中は走らない。


どうすればいいんだ

というわけでRailsを再起動しましょう。編集するたびに再起動しましょう。

とかやってると6回ぐらい再起動したあたりで精神が崩壊して最悪の場合死に至るのでおすすめできない。


本当の対処

精神を崩壊させたくなかったので調べたところ、

Rails.application.config.to_prepare を使えばproduction環境なら最初の一回だけ読んでくれて、development環境ならリクエストの度に読み込む、というのを実現してくれます。

今回のソースで言うと、以下のようになります。


config/initializers/initialize_adapter.rb

Rails.application.config.to_prepare do

ExternalServiceAdapter.configure do |config|
config.api_key = 'my_api_key'
end
end


これで ExternalServiceAdapterを編集してもapi_keyは消えません。

依存の少ないコードを書きつつ、開発も快適に進められます。


参考リンク

http://guides.rubyonrails.org/configuring.html


動作確認バージョン


  • Ruby 2.1.3

  • Rails 4.1.6