Ruby on Railsでメソッドが定義されているときに未定義メソッドエラーが発生する
概要
Ruby on Rails アプリで、コードを変更すると (たとえば、5 行目を i = f1 から i = f2 に変更すると、次のエラーが発生します。
これは私のコードです
class Api::V1::AppController < ApplicationController
def login
c = Master::Utilities.new
i = c.f1
z = c.f2
render json: {m: 'login' , msg: "hello" , data: "#{z} - #{i}" } , status: :ok
end
end
変更を元に戻しても問題は解決しません。 このエラーが発生した後、Pumaを再起動すると、コードを変更せずにすべてが再び正常に戻ります。
これらは私のコードです
このコードを config pplication.rb で使用してコードを自動ロードします
config.paths.add Rails.root.join('lib').to_s, eager_load: true
Ruby on Rails を初めて使用するので、コードに小さな間違いがあると思いますが、どこが間違っているのかわかりません。
ありがとう
解決策
ここで問題が発生しているのは、ファイルを編集すると、rails が Master::Utilities.new への呼び出しを認識し、Master::Utilities の定義を再ロードすることです。しかし、この部分になると次のようになります。
Dir[File.join(__dir__, 'code', '*.rb')].each { |file| require file }
…たとえば、lib/master/code/1.rb がすでにロードされていることがわかります。 (require は、すでにロードされているファイルを再ロードしません!)。
したがって、メソッド定義はどれも定義されていないため、事実上、インスタンス メソッドのない Master::Utilities クラスが作成されます。
簡単で最小限の修正は、上記の require を load に置き換えて、「ファイルが以前にロードされた場合でも、常にファイルをロードする」と明示的に指定することです。
Dir[File.join(__dir__, 'code', '*.rb')].each { |file| load file }
ただし、これは Ruby/Rails でコードを構造化する非常に珍しい方法であることを指摘しておきます。おそらく、より従来的なアプローチに従うほうが、より多くのメリットが得られるでしょう。
単一クラスの定義を複数のファイルに分割することにはどのような利点やロジックがありますか?メソッドが定義されている場所を探したい場合、すべてを 1 か所にまとめるか、論理モジュールに分割する方が簡単ではないでしょうか。
「クラスを 1 か所でのみ定義し、クラス名をファイル名と一致させる」という規則に従えば、Rails での一括読み込みはすぐにスムーズに機能します。たとえば、次のようにすることもできます。
# lib/master/utilities.rb
module Master
class Utilities
def f1
# ...
end
def f2
# ...
end
end
end
または:
# lib/master/utilities/meaningful_name_1.rb
module Master
module Utilities
class MeaningFulName1
def f1
# ...
end
end
end
end
# lib/master/utilities/meaningful_name_2.rb
module Master
module Utilities
class MeaningFulName2
def f2
# ...
end
end
end
end
あるいは、本当にすべてのメソッドを 1 つの巨大なクラスに入れて、フォルダー内のすべてのファイルを自動的にロードしたい場合は (非常にまとまりがないように思えますが!)、メタプログラミングを書くこともできます。 String#classify を使用してファイル名をモジュール名に変換します。