LoginSignup
63
52

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-10-06

外部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は消えません。
依存の少ないコードを書きつつ、開発も快適に進められます。

参考リンク

動作確認バージョン

  • Ruby 2.1.3
  • Rails 4.1.6
63
52
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
52