How does RoR's "magic" namespace resolution work?

ruby, ruby-on-rails

Solution

Rails' "Magic" makes extensive use of `method_missing` and `const_missing`.

When you try and call a method that is not defined, ruby fires a call to `method_missing`. This is used by libraries like `ActiveRecord` to implement dynamic finders.

method_missing example:

`SomeModel.find_by_some_field("some_value")` is not defined.

This calls `SomeModel.method_missing(:find_by_some_field, "some_value")`.

ActiveRecord then translates this call to `SomeModel.where(:some_field => "some_value")

(for performance purposes, ActiveRecord then dynamically defines this method, so next time `find_by_some_field` is defined)

const_missing example:

`SomeModel` has not yet been required.

The Ruby interpreter calls `const_missing` with the param `"SomeModel`"

Rails follows the convention `"SomeModel"` should be defined in a file called `some_model.rb` so `const_missing` just tries `require "some_model"`.

Problem

I've come from using Python and I'm very confused as to how the "magic" of Ruby on Rails works. 1. There are no require statements anywhere In Python, in order to access functions from anywhere, you must import. I assume it's the same for base ruby. But when using rails, I can call hidden variables and functions, defined in other modules, without any require statements on the top of the page. E.g. I can have a file as such: ``` class CartsController < ApplicationController .... def show begin @cart = Cart.find(params[:id]) rescue ActiveRecord::RecordNotFound logger.error "Attempt to access invalid cart #{params[:id]}" redirect_to store_url, notice: 'Invalid cart' end end ``` Where logger, redirect, and the such are all not defined. Does it simply inherit from ApplicationController up some convoluted tree, or does it somehow access those namespaces through other mechanisms? 2. Using methods that don't exist This is valid rails code ``` current_item = line_items.find_by_product_id(product_id) ``` where find_by_products_id has not been defined anywhere and yet, Rails somehow dynamically "creates" the method on the fly. Any technical insight on how this is done? Thanks for your help!

Original source