Skip to content

Railtie.respond_to_missing? creates an instance unexpectedly #44761

@eregon

Description

@eregon

Steps to reproduce

The code is

def respond_to_missing?(name, _)
instance.respond_to?(name) || super
end

This can lead to very confusing bugs, because it's not safe to e.g. check respond_to?(:ruby2_keywords, true) on Railtie or any of the subclasses.

So this line in Rails 6.1 actually creates an instance of Railtie, that's very likely unexpected:

ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)

https://github.com/rails/rails/blob/6-1-stable/railties/lib/rails/railtie.rb

An example bug caused by this is RSpec for instance can't use respond_to?(:ruby2_keywords, true) when mock'ing ::Rails.application (and so defining methods on the singleton class of the ::Rails.application).
(details in rspec/rspec-mocks#1385 (comment))

In short, this basically breaks respond_to? (or unintentionally creates instances of them) on Railtie and all its subclasses (on the class objects themselves), and so makes it difficult to check if e.g. some method defined is available on the class.

I think ideally Rails should never define respond_to_missing? on modules/classes objects themselves, it should only do so for instances of classes.

A workaround for the specific case of checking if ruby2_keywords is available is to use Module.private_method_defined?(:ruby2_keywords) instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions