2

We have a Rails application. There is a class in lib called PriorityFilter. It's a simple PORO class. It doesn't explicitly inherit from other classes and it doesn't include any modules. However, if I run Rails console I can see that the class includes a number of modules:

irb(main):002:0> PriorityFilter.included_modules
=> [ActiveSupport::ToJsonWithActiveSupportEncoder, ActionView::Helpers::NumberHelper, PP::ObjectMixin, ActiveSupport::Dependencies::Loadable, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Tryable, Kernel]

The class is used in a view helper, to prepare data for rendering a template. If I place a debugger brake point in the view helper and check included modules, there are even more modules in the list:

(byebug) PriorityFilter.included_modules
[ActiveSupport::ToJsonWithActiveSupportEncoder, ActionView::Helpers::UrlHelper, ApplicationHelper, DateTimeHelper, Aligni::DateTimeFormatter, ActiveJob::TestHelper, UnitHelper, ActionView::Helpers::TextHelper, ActionView::Helpers::TagHelper, ActionView::Helpers::OutputSafetyHelper, ActionView::Helpers::CaptureHelper, ActionView::Helpers::SanitizeHelper, ActionView::Helpers::NumberHelper, PP::ObjectMixin, ActiveSupport::Dependencies::Loadable, JSON::Ext::Generator::GeneratorMethods::Object, ActiveSupport::Tryable, Kernel]

Among them are some helpers, such as ApplicationHelper, DateTimeHelper and UnitHelper that are actually defined in the application code, not Rails.

We checked thoroughly and these helpers are not explicitly included in this class (or other similar classes) anywhere in our application code. Because of that, I suspect that Rails does that. The questions are:

  1. Is it true that Rails does that for all classes in lib?
  2. Where does Rails include those modules?
  3. Are different modules included based on the context where a class is used? Is there a way to find out which modules will be included?
  4. Is there a way to control the list of included modules, via some configuration option? (I understand that modules can be explicitly included and that they can be included/excluded in runtime with methods available on every object.)
2

1 Answer 1

1

Your class, unless specified otherwise, inherits from Object and the ActiveSupport adds its own extensions (also) to Object class, like here, with ActiveSupport::ToJsonWithActiveSupportEncoder for example:

[Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
  klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
end

so to answer your specific questions:

  1. No, if you write class that inherits from BasicObject, none of it will be included, most probably.
  2. In various places, I gave you one example, you can search for another ones.
  3. No, it's based on inheritance chain.
  4. No, as far as I know.

I'm not sure though, how are the helpers included. I'd try something like this to find it out, with the usage of included hook:

module ApplicationHelper
  def self.included(base)
    binding.pry # or any other debugger
  end
end

And then I'd start the application and see the backtrace, maybe it would work.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your answer. I'm aware of ActiveSupport core extensions that are added to all instances of Object (#blank?, #try, etc). However, in the example I described, some modules from the application code (not Rails) are included into classes that don't include them explicitly. Do you know where that happens? Also, why would some helpers from the application be included in a class and others not?
@Strika oh, sorry, I didn't read this carefully enough. I edited the answer to provide possible way to find out where it comes from, but I'm not sure if it's gonna work - let me know if it isn't, maybe we could figure some other way.
I accepted this answer since the advice helped our team find a couple of smelly spots in our application. One was in tests where several of these helpers were included directly in Object, which lead to the situation I described. Also, other points you mentioned are correct and the tip about using BasicObject is great.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.