1 はじめに

本ガイドでは、Railsアプリケーションの「自動読み込み」「再読み込み」「eager loading」について解説します

通常のRubyプログラムのクラスでは、依存関係のあるプログラムを明示的に読み込む必要があります。たとえば、以下のコントローラではApplicationControllerクラスやPostクラスを用いており、通常、それらを呼び出すにはrequireする必要があります。

# Railsではこのように書かないこと
require "application_controller"
require "post"
# Railsではこのように書かないこと

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

Railsアプリケーションでは上のようなことはしません。アプリケーションのクラスやモジュールはどこででも利用できます。

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

通常のRailsアプリケーションでrequire呼び出しを行うのは、libディレクトリにあるものや、Ruby標準ライブラリ、Ruby gemなどを読み込むときだけです。そのため、これらのような自動読み込みパスに属さないものについてはすべて後述します。

Railsではこの機能を提供するため、いくつものZeitwerkローダーを開発者の代わりに管理しています。

2 プロジェクトの構造

Railsアプリケーションで使うファイル名は、そこで定義されている定数名と一致しなければなりません。ファイル名はディレクトリ名と合わせて名前空間として振る舞います。

たとえば、app/helpers/users_helper.rbファイルではUsersHelperを定義すべきですし、app/controllers/admin/payments_controller.rbではAdmin::PaymentsControllerを定義すべきです。

デフォルトのRailsは、ファイル名をString#camelizeメソッドで活用するようZeitwerkを設定します。たとえば、app/controllers/users_controller.rbから以下のようにUsersControllerという定数を定義します。

"users_controller".camelize # => UsersController

このような活用形をカスタマイズする方法については、本ガイドの「活用形をカスタマイズする」で後述します。

詳しくはZeitwerkのドキュメントを参照してください。

3 config.autoload_paths

自動読み込みパス(オートロードパス: autoload path)とは、その中身が自動読み込みの対象となるアプリケーションディレクトリ(app/modelsなど)のリストを指します。これらのディレクトリはルート名前空間であるObjectを表します。

Zeitwerkのドキュメントでは自動読み込みのパスをルートディレクトリと呼んでいますが、本ガイドでは「自動読み込みパス」と呼びます。

自動読み込みパスの下にあるファイル名は、Zeitwerkのドキュメントに記載されているとおりに定義された定数と一致しなければなりません。

デフォルトでは、あるアプリケーションの自動読み込みパスは次のもので構成されています。アプリケーションの起動時にappの下にあるすべてのサブディレクトリ(assetsjavascriptviewsは除く)と、アプリケーションが依存する可能性のあるエンジンの自動読み込みパスです。

たとえば、app/helpers/users_helper.rbUsersHelperが実装されていれば、そのモジュールは以下のように自動読み込み可能になります。したがってrequire呼び出しは不要です(し、書くべきではありません)。

$ rails runner 'p UsersHelper'
UsersHelper

Railsの自動読み込みパスには、appの下のあらゆるカスタムディレクトリも自動的に追加されます。たとえば、アプリケーションにapp/presentersディレクトリがあれば、自動読み込みの設定を変更しなくてもapp/presentersの下に置かれたものをすぐ利用できます。

デフォルトの自動読み込みパスの配列は、config/application.rbまたはconfig/environments/*.rbで以下のようにconfig.autoload_pathsに追加することで拡張可能です。

module MyApplication
  class Application < Rails::Application
    config.autoload_paths << "#{root}/extras"
  end
end

また、Railsエンジンはエンジンクラスの本文内やエンジン独自のconfig/environments/*.rbにあるものを自動読み込みパスに追加することも可能です。

ActiveSupport::Dependencies.autoload_pathsはくれぐれも改変しないでください。自動読み込みパスを変更するpublicなインターフェイスはconfig.autoload_pathsの方です。

アプリケーションの起動中は、自動読み込みパス内のコードは自動で読み込まれません(特にconfig/initializers/*.rbの中)。正しい方法については、後述のアプリケーション起動時の自動読み込みを参照してください。

自動読み込みパスは、Rails.autoloaders.mainオートローダーによって管理されます。

4 config.autoload_once_paths

クラスやモジュールを再読み込みせずに自動読み込みできるようにしたい場合があります。autoload_once_pathsには、自動読み込みするが再読み込みはしないコードの保存場所を指定します。

このコレクションはデフォルトでは空ですが、config.autoload_once_pathsに追加する形で拡張可能です。たとえば以下はconfig/application.rbまたはconfig/environments/*.rbに書けます。

module MyApplication
  class Application < Rails::Application
    config.autoload_once_paths << "#{root}/app/serializers"
  end
end

また、Railsエンジンはエンジンクラスの本文内やエンジン独自のconfig/environments/*.rbにあるものを自動読み込みパスに追加することも可能です。

app/serializersconfig.autoload_once_pathsに追加すると、app/の下のカスタムディレクトリであってもRailsはこれを自動読み込みパスと見なさなくなります。この設定を行うと、このルールが上書きされます。

これは、Railsフレームワーク自体のような、再読み込みが可能な場所でキャッシュされるクラスやモジュールで重要になります。

たとえば、Active JobシリアライザをActive Jobの中に保存するとします。

# config/initializers/custom_serializers.rb
Rails.application.config.active_job.custom_serializers << MoneySerializer

再読み込みが発生しても、Active Jobそのものは再読み込みされず、自動読み込みパスにあるアプリケーションコードとエンジンコードのみが再読み込みされます。

このMoneySerializerを再読み込み可能にすると、改変バージョンのコードを再読み込みしてもActive Job内に保存されるそのクラスのオブジェクトに反映されないので、混乱が生じる可能性があります。実際にMoneySerializerを再読み込み可能にすると、Rails 7以降ではそのようなイニシャライザでNameErrorが発生します。

別のユースケースは、以下のようにフレームワークのクラスをdecorateするエンジンの場合です。

initializer "decorate ActionController::Base" do
  ActiveSupport.on_load(:action_controller_base) do
    include MyDecoration
  end
end

この場合、イニシャライザが実行される時点ではMyDecorationに保存されているモジュールオブジェクトがActionController::Baseの先祖となるので、MyDecorationを再読み込みしても先祖への継承チェイン(ancestor chain)に反映されず、無意味です。

autoload_once_pathsのクラスやモジュールはconfig/initializersで自動読み込み可能です。すなわち、以下の設定を行うことで動くようになります。

# config/initializers/custom_serializers.rb
Rails.application.config.active_job.custom_serializers << MoneySerializer

技術的には、onceオートローダーによって管理されるクラスやモジュールは、:bootstrap_hookより後に実行される任意のイニシャライザで自動読み込みが可能です。

autoload_once_pathsは、Rails.autoloaders.onceで管理されます。

5 $LOAD_PATH{#load_path}

自動読み込みパスは、デフォルトで$LOAD_PATHに追加されます。ただしZeitwerkは内部で絶対ファイル名を用いており、アプリケーション内では自動読み込み可能なファイルをrequire呼び出しすべきではないため、それらのディレクトリは実際には不要です。以下のフラグを用いることで、$LOAD_PATHに自動読み込みパスを追加しないようにできます。

config.add_autoload_paths_to_load_path = false

こうすることで探索が削減され、正当なrequireが少し速くなる可能性もあります。また、アプリケーションでBootsnapを使っている場合は、このライブラリが不要なインデックスを構築しなくても済むため、必要なメモリ使用量を節約できます。

6 再読み込み

Railsアプリケーションのファイルが変更されると、クラスやモジュールを自動的に再読み込みします。

正確に言うと、Webサーバーが実行中の状態でアプリケーションのファイルが変更されると、Railsは次のリクエストが処理される直前に、mainオートローダが管理しているすべての定数をアンロードします。これによって、アプリケーションでリクエスト継続中に使われるクラスやモジュールが自動読み込みされるようになり、続いてファイルシステム上の現在の実装が反映されます。

再読み込みは有効にも無効にもできます。この振る舞いを制御するのはconfig.cache_classes設定です。これはdevelopmentモードではデフォルトでfalse(再読み込みが有効)、productionモードではtrue(再読み込みが無効)になります。

デフォルトのRailsは、変更されたファイルをイベンテッドファイルモニタで検出しますが、自動読み込みパスを調べてファイル変更を検出することも可能です。これは、config.file_watcherの設定で制御されます。

Railsコンソールでは、 config.cache_classesの値にかかわらずファイルウォッチャーは動作しません(通常、コンソールセッションの最中に再読み込みが行われると混乱を招く可能性があるためです)。一般にコンソールセッションは、 個別のリクエストと同様に変化しない、一貫したアプリケーションクラスとモジュールのセットによって提供されることが望まれます。

ただし、コンソールでreload!を実行することで強制的に再読み込みできます。

irb(main):001:0> User.object_id
=> 70136277390120
irb(main):002:0> reload!
Reloading...
=> true
irb(main):003:0> User.object_id
=> 70136284426020

上のように、User定数に保存されているクラスオブジェクトは、再読み込みすると異なるものに変わります。

6.1 古くなったオブジェクトの再読み込み

Rubyには、メモリ上のクラスやモジュールを真の意味で再読み込みする手段もなければ、既に利用されているすべてのクラスやモジュールに再読み込みを反映する手段もないことを理解しておくことが、きわめて重要です。技術的には、Userクラスを「アンロード」することは、Object.send(:remove_const, "User")User定数を削除するということです。

たとえば、Railsコンソールセッションで以下をチェックしてみます。

irb> joe = User.new
irb> reload!
irb> alice = User.new
irb> joe.class == alice.class
=> false

joeは元のUserクラスのインスタンスです。再読み込みが発生すると、このUser定数はそれまでと異なる、再読み込みされたクラスとして評価されます。aliceは新たに読み込んだUserクラスのインスタンスですが、joeのクラスはそうではなく、クラスが古くなっています(stale)。この場合はreload!を再度呼び出す代わりに、joeを再度定義するか、IRBサブセッションを起動するか、単に新しいコンソールセッションを起動することでも解決します。

また、再読み込み可能なクラスを、再読み込みされない場所でサブクラス化している場合にもこの問題が発生する可能性があります。

# lib/vip_user.rb
class VipUser < User
end

Userが再読み込みされてもVipUserは再読み込みされないので、VipUserのスーパークラスは元の古いクラスのオブジェクトのままです。

結論: 再読み込み可能なクラスやモジュールをキャッシュしてはいけません

7 アプリケーション起動時の自動読み込み

起動中のアプリケーションは、onceオートローダが管理するautoload_once_pathsからの自動読み込みが可能です(詳しくは前述のconfig.autoload_once_pathsを参照)。

ただし、mainオートローダが管理している自動読み込みパスからの自動読み込みはできません。これは、config/initializersにあるコードや、アプリケーションやエンジンのイニシャライズについても同様です。

その理由は、イニシャライザはアプリケーション起動時に1度しか実行されないためです。サーバーを再起動すれば、新しいプロセスで再度実行されますが、再読み込みはサーバーを再起動しないので、イニシャライザは実行されません。主な2つのユースケースを見てみましょう。

7.1 ユースケース1: 起動中に、再読み込み可能なコードを読み込む

7.1.1 起動時と各再読み込みの両方で実行される自動読み込み

mainオートローダーが管理しているapp/servicesApiGatewayという再読み込み可能なクラスがあるとします。そしてアプリケーション起動時にエンドポイントを設定する必要が生じたとします。以下のように書くとエラーになります。

# config/initializers/api_gateway_setup.rb
ApiGateway.endpoint = "https://example.com" # NameError

イニシャライザは再読み込み可能な定数を参照できないので、to_prepareブロックを使って、再読み込み時に実行されるコードをラップする必要があります。この部分は起動時に読み込まれ、また再読み込みのたびに読み込まれるようになります。

# config/initializers/api_gateway_setup.rb
Rails.application.config.to_prepare do
  ApiGateway.endpoint = "https://example.com" # 正しい
end

歴史的な理由により、このコールバックは2回実行される可能性があります。ここで実行するコードは冪等でなければなりません。

7.1.2 起動時にのみ実行される自動読み込み

再読み込み可能なクラスとモジュールは、after_initializeブロックでも自動読み込みが可能です。これらは起動時に実行されますが、再読み込み時には再実行されません。例外的な状況では、この振る舞いにしたいこともあります。

以下のようなプリフライトチェックはそうしたユースケースのひとつです。

# config/initializers/check_admin_presence.rb
Rails.application.config.after_initialize do
  unless Role.where(name: "admin").exists?
    abort "adminロールが存在しません。データベースのseedを行ってください。"
  end
end

7.2 ユースケース2: 起動中に、キャッシュされたままのコードを読み込む

設定によっては、何らかのクラスやモジュールのオブジェクトを受け取って、それを再読み込みされない場所に保存するものもあります。こうした設定では、コードの編集の結果がキャッシュ済みの古いオブジェクトに反映されないため、設定に渡すものは再読み込み可能にしないことが重要です。

そうした例の1つがミドルウェアです。

config.middleware.use MyApp::Middleware::Foo

再読み込みを行っても、このミドルウェアスタックには反映されないので、MyApp::Middleware::Fooが再読み込み可能になっていると混乱の元になります(その実装を変更しても何も反映されません)。

別の例は、Active Jobシリアライザです。

# config/initializers/custom_serializers.rb
Rails.application.config.active_job.custom_serializers << MoneySerializer

初期化時にMoneySerializerが評価したものは、すべてこのカスタムシリアライザにプッシュされ、そのオブジェクトは再読み込み時にも残り続けます。

さらに別の例は、Railtieやエンジンがモジュールをincludeしてフレームワークのクラスをdecorateする場合です。たとえば、turbo-railsActiveRecord::Baseを以下のようにdecorateします。

initializer "turbo.broadcastable" do
  ActiveSupport.on_load(:active_record) do
    include Turbo::Broadcastable
  end
end

これにより、ActiveRecord::Baseの先祖への継承チェインにモジュールオブジェクトが追加されます。しかし再読み込みが発生してもTurbo::Broadcastableの変更は反映されないので、先祖への継承チェインには元のオブジェクトが引き続き残ります。

すなわち、こうしたクラスやモジュールは再読み込み可能にできません

そのようなクラスやモジュールを起動時に参照する最も手軽な方法は、自動読み込みパスに属さないディレクトリでそれらを定義することです。たとえばlib/に置くのが妥当でしょう。lib/はデフォルトでは自動読み込みパスに属しませんが、$LOAD_PATHには属しているので、requireするだけで読み込めます。

別の方法は、上述のように、それらをautoload_once_pathsディレクトリで定義して自動読み込みすることです(詳しくは前述のconfig.autoload_once_pathsを参照)。

7.3 ユースケース3: エンジンで使うアプリケーションのクラスを設定する

あるエンジンが、ユーザーをモデリングする再読み込み可能なアプリケーションクラスと連携する場合、そのための設定ポイントが以下のようになっていると、エラーになります。

# config/initializers/my_engine.rb
MyEngine.configure do |config|
  config.user_model = User # NameError
end

再読み込み可能なアプリケーションコードをエンジンで正しく扱うには、代わりにアプリケーションのクラス名を文字列で設定する必要があります。

# config/initializers/my_engine.rb
MyEngine.configure do |config|
  config.user_model = "User" # OK
end

これで、実行時にconfig.user_model.constantizeで現在のクラスオブジェクトを得られるようになります。

8 eager loading

一般的にproduction的な環境では、アプリケーションの起動時にアプリケーションコードをすべて読み込んでおく方が望ましいと言えます。eager loading(一括読み込み)はすべてをメモリ上に読み込むことでリクエストに即座に対応できるように備え、CoW(コピーオンライト)との相性にも優れています。

eager loadingはconfig.eager_loadフラグで制御します。これはproduction以外のすべての環境でデフォルトで無効になっています。rakeタスクが実行されると、config.eager_loadconfig.rake_eager_loadで上書きされ、デフォルトではfalseになります。つまり、production環境で実行するrakeタスクは、デフォルトではアプリケーションをeager loadingしません。

ファイルがeager loadingされる順序は未定義です。

eager loading中に、RailsはZeitwerk::Loader.eager_load_allを呼び出します。これはすべてのZeitwerkが管理している依存gemもeager loadされていることを保証します。

9 STI(単一テーブル継承)

単一テーブル継承機能は、lazy loading(遅延読み込み)との相性があまりよくありません。一般に単一テーブル継承のAPIが正しく動作するには、STI階層を正しく列挙できる必要があるためです。lazy loadingでは、クラスが参照されるまでクラス読み込みは遅延されます。まだ参照されていないものは列挙できないのです。

ある意味、アプリケーションは読み込みモードにかかわらずSTI階層をeager loadする必要があります。

もちろん、アプリケーションが起動時にeager loadするのであれば目的は既に達成されます。そうでない場合、実際にはデータベース内の既存の型をインスタンス化すれば十分です。developmentモードやtestモードであれば普通はこれで問題ありません。これを行う方法の1つは、このモジュールをlibディレクトリに配置することです。

module StiPreload
  unless Rails.application.config.eager_load
    extend ActiveSupport::Concern

    included do
      cattr_accessor :preloaded, instance_accessor: false
    end

    class_methods do
      def descendants
        preload_sti unless preloaded
        super
      end

      # データベース内にあるすべての型を定数化する。
      # その分ディスク容量が余分に必要だが、
      # STIのAPIに配慮されていれば実際には問題ではない。
      #
      # store_full_sti_classがtrue(デフォルト)であることが前提
      def preload_sti
        types_in_db = \
          base_class.
            unscoped.
            select(inheritance_column).
            distinct.
            pluck(inheritance_column).
            compact

        types_in_db.each do |type|
          logger.debug("Preloading STI type #{type}")
          type.constantize
        end

        self.preloaded = true
      end
    end
  end
end

続いて、プロジェクトのSTIルートクラスでincludeします。

# app/models/shape.rb
require "sti_preload"

class Shape < ApplicationRecord
  include StiPreload # rootクラスにのみ存在する
end
# app/models/polygon.rb
class Polygon < Shape
end
# app/models/triangle.rb
class Triangle < Polygon
end

10 活用形をカスタマイズする

デフォルトのRailsは、指定のファイル名やディレクトリ名がどんな定数を定義すべきかを知るのにString#camelizeを利用します。たとえば、posts_controller.rbというファイル名の場合はPostsControllerが定義されていると認識しますが、これは"posts_controller".camelizePostsControllerを返すからです。

場合によっては、特定のファイル名やディレクトリ名が期待どおりに活用されないことがあります。たとえばhtml_parser.rbはデフォルトではHtmlParserを定義すると予測できます。しかしクラス名をHTMLParserにしたい場合はどうすればよいでしょうか。この場合のカスタマイズ方法はいくつか考えられます。

最も手軽な方法は、以下のように略語を定義することです。

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym "HTML"
  inflect.acronym "SSL"
end

これによって、Active Supportによる活用方法がグローバルに反映されます。 これで問題のないアプリケーションもありますが、以下のようにデフォルトのインフレクタに上書き用のコレクションを渡して、Active Supportの個別の基本語形をキャメルケース化する方法をカスタマイズすることも可能です。

Rails.autoloaders.each do |autoloader|
  autoloader.inflector.inflect(
    "html_parser" => "HTMLParser",
    "ssl_error"   => "SSLError"
  )
end

しかしデフォルトのインフレクタはString#camelizeをフォールバック先として使っているので、この手法は依然としてString#camelizeに依存しています。Active Supportの活用形機能に一切依存せずに活用形を絶対的に制御したい場合は、以下のようにZeitwerk::Inflectorのインスタンスをインフレクタとして設定します。

Rails.autoloaders.each do |autoloader|
  autoloader.inflector = Zeitwerk::Inflector.new
  autoloader.inflector.inflect(
    "html_parser" => "HTMLParser",
    "ssl_error"   => "SSLError"
  )
end

この場合は、インスタンスに影響するようなグローバル設定が存在しないので、活用形は1つに決定されます。

カスタムインフレクタを定義して柔軟性を高めることも可能です。詳しくはZeitwerkドキュメントを参照してください。

10.1 活用形のカスタマイズはどこで行うべきか

アプリケーションがonceオートローダを使わない場合、上記のスニペットはconfig/initializersに保存できます。たとえば、Active Supportを使う場合はconfig/initializers/inflections.rbに書き、それ以外の場合はconfig/initializers/zeitwerk.rbに書くとよいでしょう。

アプリケーションがonceオートローダを使う場合は、この設定を別の場所に移動するか、config/application.rbのアプリケーションクラスの本体から読み込む必要があります。onceオートローダーはブートプロセスの早い段階でインフレクタを利用するからです。

11 自動読み込みとRailsエンジン

Railsエンジンは、親アプリケーションのコンテキストで動作し、エンジンのコードの自動読み込み、再読み込み、eager loadingは親アプリケーションによって行われます。アプリケーションをzeitwerkモードで実行する場合は、エンジンのコードもzeitwerkモードで読み込まれます。アプリケーションをclassicモードで実行する場合は、エンジンのコードもclassicモードで読み込まれます。

Railsが起動すると、エンジンのディレクトリが自動読み込みパスに追加されますが、自動読み込みという観点からは何の違いもありません。自動読み込みの主な入力は自動読み込みパスであり、そのパスがアプリケーションのソースツリーであるか、エンジンのソースツリーであるかは無関係です。

たとえば、以下のアプリケーションはDeviseを使っています。

% bin/rails runner 'pp ActiveSupport::Dependencies.autoload_paths'
[".../app/controllers",
 ".../app/controllers/concerns",
 ".../app/helpers",
 ".../app/models",
 ".../app/models/concerns",
 ".../gems/devise-4.8.0/app/controllers",
 ".../gems/devise-4.8.0/app/helpers",
 ".../gems/devise-4.8.0/app/mailers"]

このエンジンが親アプリケーションの自動読み込みを制御するのであれば、これまでどおりにエンジンを書けます。

しかし、エンジンがRails 6や6.1以降をサポートしており、親アプリケーションの自動読み込みを制御しないのであれば、classicモードとzeitwerkモードのどちらの場合でも実行可能になるように書かなければなりません。そのためには、以下を考慮する必要があります。

  1. classicモードで特定の箇所で何らかの定数を確実に読み込ませるためにrequire_dependency呼び出しが必要な場合は、require_dependency呼び出しを書く。これはzeitwerkモードでは不要ですが、zeitwerkモードでも問題なく動作します。

  2. classicモードは定数名をアンダースコア化してファイル名を求め("User" -> "user.rb")、逆にzeitwerkモードではファイル名をcamelizeして定数名を求める("user.rb" -> "User")。両者はほとんどの場合一致しますが、HTMLParserのように大文字が連続すると一致しなくなります。互換性を保つ最も手軽な方法は、大文字が連続する名前を避けることです(この場合は"HtmlParser"にします)。

  3. classicモードでは、app/model/concerns/foo.rbファイルにFooConcerns::Fooを両方定義することを容認するが、zeitwerkモードではFooのみの定義しか許さない。互換性のためにはFooを定義してください。

12 テスト

12.1 手動テスト

zeitwerk:checkタスクを使うと、プロジェクトツリーが上述の命名規則に沿っているかを手軽に手動チェックできます。たとえば、classicモードからzeitwerkモードに移行するときや、何かを修正するときにこのタスクを使うと便利です。

% bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!

アプリケーションの設定次第では他にも出力される可能性がありますが、末尾に"All is good!"が表示されるかどうかをチェックすれば十分です。

12.2 自動テスト

プロジェクトが正しくeager loadingされているかどうかをテストスイートで検証するのはよい方法です。

Zeitwerkの命名規則やその他に発生しうるエラー条件をカバーできます。詳しくはRailsテスティングガイドeager loadingをテストするを参照してください。

13 トラブルシューティング

ローダーの振る舞いを追跡するベストの方法は、ローダーの活動を調べることです。

最も手軽な方法は、フレームワークのデフォルトが読み込まれた後で以下をconfig/application.rbに設定することです。

Rails.autoloaders.log!

これにより、標準出力にトレースが出力されます。

ログをファイルに出力したい場合は、上の代わりに以下を設定します。

Rails.autoloaders.logger = Logger.new("#{Rails.root}/log/autoloading.log")

Railsロガーは、config/application.rbが実行される時点ではまだ利用できません。Railsロガーを使いたい場合は、イニシャライザの設定を以下のように変更します。

# config/initializers/log_autoloaders.rb
Rails.autoloaders.logger = Rails.logger

14 Rails.autoloaders

アプリを管理するZeitwerkのインスタンスは以下で利用できます。

Rails.autoloaders.main
Rails.autoloaders.once

以下の述語メソッドは引き続きRails 7でも利用可能で、trueを返します。

Rails.autoloaders.zeitwerk_enabled?

フィードバックについて

Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。

原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨

本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。

Railsガイド運営チーム (@RailsGuidesJP)

支援・協賛

Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。

  1. Star
  2. このエントリーをはてなブックマークに追加