web-dev-qa-db-ja.com

Rails 5:本番環境でlibファイルをロードする

私のアプリの1つをRails 4.2.6からRails 5.0.0にアップグレードしました。 アップグレードガイド によると、オートロード機能は本番環境ではデフォルトで無効になっています。

application.rbファイルにすべてのlibファイルをautoloadでロードするので、運用サーバーでは常にエラーが発生します。

module MyApp
    class Application < Rails::Application
        config.autoload_paths += %W( lib/ )
    end
end

今のところ、私はconfig.enable_dependency_loadingtrueに設定しましたが、もっと良い解決策があるのだろうか。自動ロードがデフォルトで本番環境で無効になっている理由があるはずです。

103
Tobias

自動ロードは、スレッドの安全性のために本番環境では無効になっています。リンクをありがとうございました@Зелёный。

Github で推奨されているように、私はlibディレクトリのappフォルダにlibファイルを保存することによってこの問題を解決しました。 appフォルダー内のすべてのフォルダーはRailsによって自動的にロードされます。

28
Tobias

Rails 5に移行した後の私の変更点の一覧:

  1. App内のすべてのコードはdevでautoloaded、prodでeager loadedであり、最も重要なのは開発中autoreloadedであるため、libdirをappname__に配置します。変更を加えるたびにサーバーを再起動する必要はありません。
  2. requirename__ステートメント内の自分のクラスを指しているlibname__ステートメントはすべて、それらのファイル/ディレクトリ名が正しい場合はすべて自動ロードされるため、requirename__ステートメントをそのままにしておくと自動再ロードが中断される可能性があります。さらに詳しい情報 ここ
  3. すべての環境でconfig.eager_load = trueを設定して、devでコードロードの問題を積極的に確認してください。
  4. 「循環依存」エラーを回避するために、スレッドで遊ぶ前にRails.application.eager_load!を使用してください。
  5. Ruby/Railsエクステンションがある場合は、そのコードを古いlibname__ディレクトリ内に残し、それらをイニシャライザから手動でロードします。これにより、それに依存する可能性がある追加のロジックの前に拡張機能が確実にロードされます。

    # config/initializers/extensions.rb
    Dir["#{Rails.root}/lib/Ruby_ext/*.rb"].each { |file| require file }
    Dir["#{Rails.root}/lib/Rails_ext/*.rb"].each { |file| require file }
    
134
Lev Lukomsky

Githubのコメントでakostadinovに言及したように、私はちょうどconfig.eager_load_pathsの代わりにconfig.autoload_pathsを使いました: https://github.com/Rails/rails/issues/13142#issuecomment-275492070

# config.autoload_paths << Rails.root.join('lib')
config.eager_load_paths << Rails.root.join('lib')

それは開発と生産環境に働きます。

#{Rails.root}/libRails.root.join('lib')に置き換えることを提案してくれてありがとう Johan

55

自動ロードがデフォルトで本番環境で無効になっている理由があるはずです。

これはこの問題についての長い議論です。 https://github.com/Rails/rails/issues/13142

19
Зелёный

これはlibの自動再読み込みを可能にし、本番環境でも動作します。

P.S私は自分の答えを変えました。今では(ステージのように)カスタム環境でも作業できるように、環境に関係なく自動ロードパスの両方に追加されます

# config/initializers/load_lib.rb
...
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
...
7
srghma

ある意味で、これは積極的なオートロード設定を一元化するためのRails 5の統一されたアプローチです。

# config/application.rb
...
config.paths.add Rails.root.join('lib').to_s, eager_load: true

# as an example of autoload only config
config.paths.add Rails.root.join('domainpack').to_s, autoload: true
...
2
pocheptsov

私のようにこれに苦しんでいる人にとっては、ディレクトリをapp/の下に置くだけでは不十分です。はい、あなたは自動ロードを取得しますが、必要ではありません 再ロード。名前空間の規約を守る必要があります

また、初期化子を使用して古いルートレベルのlibをロードすると、開発中の機能の再ロードが妨げられます。

2
Abdullah Barrak

Libフォルダをappに移動すると問題が解決しましたが、私のTwitter APIは本番環境では動作しませんでした。私は「初期化されていない定数TwitterApi」を持っていて、私のTwitter APIは私のlibフォルダにありました。私のapplication.rbにconfig.autoload_paths += Dir["#{Rails.root}/app/lib"]がありましたが、フォルダを移動する前はうまくいきませんでした。

これはトリックでした

0
Laurie

levの答えを要約すると、mv lib appは私のすべてのlibコードをオートロード/オートリロードするのに十分でした。

(Rails 6.0.0beta 3ですが、Rails 5.xでもうまく動くはずです)

0
localhostdotdev