web-dev-qa-db-ja.com

Ruby on Rails 3-各リクエストのlibディレクトリをリロードします

Rails 3アプリケーション用の新しいエンジンを作成しています。ご想像のとおり、このエンジンはアプリケーションのlibディレクトリにあります。

ただし、開発にはいくつかの問題があります。実際、エンジンで何かを変更するたびにサーバーを再起動する必要があります。

これを回避する方法はありますか?

Railsを指定して、libディレクトリまたは特定のファイルと各リクエストの要件を完全にリロードすることはできますか?

ご協力いただきありがとうございます :)

58

TL; DR

  • これをconfig/application.rbに入れます

    config.eager_load_paths += ["#{Rails.root}/lib"]

  • libファイルのrequireステートメントを削除

行け!


詳細に説明させてください。

この答えが受け入れられる理由はわかりません。なぜなら、各リクエストでのlibフォルダーのリロードには役立たないからです。最初に、Rails 2で動作すると思ったが、質問では、Rails 3であり、3.0.0のリリース日は回答の日付。

他の回答は複雑すぎるか、実際の解決策を提供していません。

私は気になっていたので少し物事を調査することにしました、そして私は人々がこれに対する回避策を持っていることを発見し、それは開発中のapp/models内にlibファイルを保存し、完了したらそれを/libに移動することを含むことさえ発見しました私たちはもっとうまくできるでしょう?


私のソリューションは以下に対してテストされています:

  • Rails 3.0.20
  • Rails 3.1.12
  • Rails 3.2.13
  • Rails 4.0.0.rc1

これをconfig/application.rbに入れてください:

# in config/application.rb
config.eager_load_paths += ["#{Rails.root}/lib"]

それだけです!™

たとえば、config/environments/development.rbに配置した場合、not workになるため、ここに配置してください。

requireステートメントもこのソリューションを機能させないため、/libコードのrequireステートメントをすべて削除してください。


このコードは暗黙的にコードを必要とするため、環境チェック(不要)を実行し、上記のコードの代わりに、次のような記述を行うことにします。

# in config/application.rb
config.eager_load_paths += ["#{Rails.root}/lib"] if Rails.env.development?

このシナリオでは、すべての非開発環境でまだ必要であるため、古いrequireステートメントに注意する必要があります。

したがって、まだ環境チェックを行うことに決めた場合は、requireステートメントの逆チェックを行ってください。さもないと噛まれてしまいます!

require "beer_creator" unless Rails.env.development?

不要なことについて段落全体を書くことも不要だと思うかもしれませんが、不要なことをするときに必要なことについて人々に警告することも必要だと思います。

このトピックについて詳しく知りたい場合は、 この小さなチュートリアル をご覧ください。

33
shime

私は上記のどれも私のために働くことができなかったので、Railsコードを少し掘り下げて、これを思いつきました:

新しいファイル:config/initializers/reload_lib.rb

if Rails.env == "development"
  lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"]) do
    Rails.application.reload_routes! # or do something better here
  end

  # For Rails 5.1+
  ActiveSupport::Reloader.to_prepare do
    lib_reloader.execute_if_updated
  end

  # For Rails pre-5.1 
  ActionDispatch::Callbacks.to_prepare do
    lib_reloader.execute_if_updated
  end

end

はい、嫌なことは知っていますが、ハックです。完全なリロードをトリガーするより良い方法があるかもしれませんが、これは私のために動作します。私の特定のユースケースは、RailsルートにマウントされたRackアプリでした。そのため、開発中に作業していたのでリロードする必要がありました。

基本的には、/ lib内のファイルが最後にロードされてから変更(タイムスタンプが変更)されているかどうかを確認し、変更された場合はリロードをトリガーします。

Config/application.rbにこれがあることにも言及するかもしれません

config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

デフォルトでは、libディレクトリ内のすべてが確実にロードされます。

いいね!

49
Patrick Hogan

Railsについて話しているので、最も簡単な方法は、 'require_dependency'を使用してlib/* .rbファイルを 'require'することです。 controller/helper/etc(app /の下の.rbファイル)がリロード作業を単に必要とするのではなく、require_dependencyを使用し、ファンキーなことをする必要がない限り。

私がその道を進む前に、働いていた唯一の解決策は hemju.com のものでしたが、開発速度のためにApplicationControllerをハックする必要は本当にありませんでした。

21
Paul Saladna

追加する必要があります

config.autoload_paths += %W(#{config.root}/lib)

config/application.rbのApplicationクラスに

https://Rails.lighthouseapp.com/projects/8994/tickets/5218-Rails-3-rc-does-not-autoload-from-lib

13
dishod

In Rails 3、これはlibファイルを自動リロードするための秘密のソースです。以下のコードは少しやり過ぎです。たとえば、それを機能させるために行ったものです。メッセージを変更できます。 YoYo#gogoで各ページがロードされるたびに画面上に表示されます。イニシャライザを削除しても同じままです。

/ config/initializers/lib_reload.rb(新しいファイル)

ActiveSupport::Dependencies.explicitly_unloadable_constants << 'YoYo'
ActiveSupport::Dependencies.autoload_once_paths.delete(File.expand_path(File.dirname(__FILE__))+'/lib')

/ lib/yo_yo.rb

class YoYo
  def gogo
    "OH HAI THERE"
  end
end

/ app/controllers/home_controller

require 'yo_yo'
class HomeController < ApplicationController
  def index
    @message = YoYo.new.gogo
  end
end
3
Jesse Wolgamott

更新された回答

私のブログですべての発見を要約します。

古い回答

私もこれに対する解決策を探しましたが、(完全を期すために、また他の人にこの方向を示すために)ここで見つけました。

Rails3.1以降、エンジンはコマンドRails plugin new my_plugin --fullを使用して簡単に生成できます。これにより、エンジンのスケルトンが生成されます。

--fullは、エンジンがインクルードアプリケーションに「マージ」されることを意味します。たとえば、インクルードアプリで定義されているかのようにコントローラーに直接アクセスできる必要があります。これにより、たとえばmy_engine/app/helpers/my_helper.rbにヘルパーファイルがあります。これは、インクルードアプリのapp/helpers/my_helper.rb helperに直接マージされます。

エンジンの名前空間を作成する別のオプション--mountableがあり、そのコントローラーなどがアプリケーションのインクルードと衝突しないようにします。これにより、例えばヘルパーはmy_engine/app/helpers/my_engine/my_helper.rbにありますが、インクルードアプリのヘルパーapp/helpers/my_helper.rbと衝突しません。

今より興味深い部分

生成されたエンジンのtestフォルダー内には、完全なRailsアプリケーション!何のためにあるのかを保持するdummyフォルダーがあります。

エンジンを開発するとき、その機能は独自に完全に機能することを意図しており、独自に完全にテストする必要もあります。したがって、別の「内」でエンジンを開発する「間違った」方法ですRails app(ただし、これは、Railsエンジンへのアプリ)、したがって理論的には、含まれるアプリケーションへのすべてのリクエストでエンジンのコードをリロードする必要もありません。

「正しい」方法はこれのようです:エンジンを開発してテストします。まるでそれが完全なRailsアプリでdummyアプリを使用しているかのようです! 「通常」で行うRailsアプリ。たとえば、エンジンが提供する機能を使用するコントローラー、モデル、ビューなどを作成します。通常、Rails sを使用してサーバーを起動することもできます。 test/dummyディレクトリでlocalhost:3000のダミーアプリにアクセスし、テストを実行すると、dummyアプリが統合テストに自動的に使用されます。

物を置く場所に注意する必要があります:

  • 別のRails app内で使用することを意図した機能はすべてmy_engine/appに入り、エンジンの機能をテストするためにのみ必要な機能はtest/dummy/appに入ります。

その後、次のようにメインアプリのGemfileにエンジンを簡単にロードできます:gem 'my_engine', :path => 'path/to/my_engine'またはGitHubにgemとして公開します。

(興味深いことに(このトピックの主題に戻って)ダミーのサーバーを起動すると、エンジンのすべての変更がサーバー内に反映されるようになります! Railsキャッシュせずにアプリ...?これがどのように起こるかわかりません。)

要約すると、エンジンは独自に完全に機能する機能を提供するため、独自に開発およびテストする必要があります。その後、安定状態に達すると、その機能を必要とする他のアプリに含めることができます。

ここに私が役に立つと思ういくつかのリソースがあります:

この回答がお役に立てば幸いです。私は一般的にまだエンジンが非常に新しいので、間違った情報があれば教えてください、そして私はそれを修正します。

1
Joshua Muheim

追加 application_controller.rbまたはベースコントローラー:

  before_filter :dev_reload if Rails.env.eql? 'development'

  def dev_reload
    # add lib files here
    ["rest_client.rb"].each do |lib_file|
      ActiveSupport::Dependencies.load_file lib_file
    end
  end

私のために働いた。

1
Haris Krajina

また、application.rbの次の行を(@dishodのソリューションに加えて)コメントアウトし、モジュール名がファイル名と同じであることを確認してください(そうでない場合、Rails =見つけることができません)

#Dir.glob("./lib/*.{rb}").each { |file| require file } # require each file from lib directory
0
vish

アプリのgem内でlibをリロードするためにRails 3.2.13で働きました:

require_dependency 'the_class'

そして

config.autoload_paths + =%W(#{config.root} /../ fantasy/lib)

0
rndrfero

in Rails 3 "load_once_paths"は "autoload_once_paths"になります。

また、明示的に何かを入れない限り空であるように見えます。

0
Avram Dorfman