Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!

like image 572
Xiv Avatar asked Apr 21 '26 10:04

Xiv


1 Answers

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".

like image 146
Matthew Rudy Avatar answered Apr 23 '26 00:04

Matthew Rudy