From 7c3caceb248553479ced4979498dc8bdfd79129e Mon Sep 17 00:00:00 2001 From: Kirill Mokevnin Date: Wed, 2 Sep 2026 12:28:17 -0400 Subject: [PATCH] Define Dotenv::Rails class-level options explicitly The options documented in the README (`Dotenv::Rails.files`, `.overwrite`, `.logger`, `.autorestore` and their writers) are configured on the class, but `delegate` only defines them on the railtie instance. They work today solely because `Rails::Railtie` privately forwards unknown class methods to `instance` via `method_missing`. That indirection means the gem's documented public API has no definition anywhere: it is absent from `Dotenv::Rails.methods`, `method(:files)` has no source location, so doc generators and editor completion can't see it, and the API depends on private Rails behavior that could be narrowed without notice. Delegating the same names from the singleton class to `instance` makes them real methods. `method_missing` remains in place as the fallback for everything else, and delegating to `instance` (rather than `config.dotenv`) keeps the custom `logger=` replay logic on the path, so behavior is unchanged. Co-Authored-By: Claude Opus 5 (1M context) --- lib/dotenv/rails.rb | 7 +++++++ spec/dotenv/rails_spec.rb | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/dotenv/rails.rb b/lib/dotenv/rails.rb index a94442f..d0135fb 100644 --- a/lib/dotenv/rails.rb +++ b/lib/dotenv/rails.rb @@ -22,6 +22,13 @@ module Dotenv class Rails < ::Rails::Railtie delegate :files, :files=, :overwrite, :overwrite=, :autorestore, :autorestore=, :logger, to: "config.dotenv" + # The documented options are configured on the class, which Rails only supports through + # `Railtie.method_missing`. Define them explicitly so they show up in `.methods`, have a + # source location, and don't depend on that forwarding. + class << self + delegate :files, :files=, :overwrite, :overwrite=, :autorestore, :autorestore=, :logger, :logger=, to: :instance + end + def initialize super config.dotenv = ActiveSupport::OrderedOptions.new.update( diff --git a/spec/dotenv/rails_spec.rb b/spec/dotenv/rails_spec.rb index 59fc678..469d2aa 100644 --- a/spec/dotenv/rails_spec.rb +++ b/spec/dotenv/rails_spec.rb @@ -74,6 +74,17 @@ end end + describe "options" do + it "are defined on the class and delegate to the instance" do + expect(Dotenv::Rails.singleton_class.instance_methods).to include( + :files, :files=, :overwrite, :overwrite=, :autorestore, :autorestore=, :logger, :logger= + ) + + Dotenv::Rails.overwrite = true + expect(Dotenv::Rails.instance.overwrite).to be(true) + end + end + it "watches other loaded files with Spring" do stub_spring(load_watcher: true) application.initialize!