Главное, что нужно понять, это то, что импорт (необходимый) в Ruby является глобальным.
Под капотом Rails требуется запись приложения, а затем требуются файлы вашей модели. Поскольку запись приложения уже требуется (хотя и в другом файле), модели и все другие биты кода, загруженные после нее, имеют к ней доступ.
Вы можете увидеть это в следующем простом примере:
# a.rb
require 'b'
require 'c'
# b.rb
class ThisIsExported; end
# c.rb
puts defined?(ThisisExported) # => 'constant'
Помните, что все классы, модули и константы являются глобальными (хотя они могут быть пространственными именами), и что это единственные вещи, «экспортируемые» из файла (ну, можно экспортировать и голые методы, но они на самом деле определены на глобальном экземпляре объекта). Итак, требование файла в Ruby - это не столько «импорт» его в конкретный файл, сколько вызов «eval» в исходном коде этого файла.
Вы можете думать об этом так, как будто Ruby просто находит и заменяет все требуемые вызовы фактическим исходным кодом этого файла ... на самом деле это не то, что происходит, а эффект тот же.
Ближайшая вещь, которую Ruby должен строго импортировать из файлов, - это уточнения, но вам все равно необходимо упаковать их в глобальный, и поведение не совсем совместимо с обычным импортом (например, defined?
не будет точным )
# a.rb
require 'b'
require 'c'
require 'd'
# b.rb
module FileSpecificModuleInclude
refine(Object) do
def patched; 'ok'; end
end
end
# c.rb
using FileSpecificModuleInclude
# It says it's not defined ....
puts defined?(patched) # => nil
# But it actually is ...
puts patched # => 'ok'
# d.rb
patched # => NoMethodError