В руководстве по Rails как подкласс Article может быть из ApplicationRecord без 'require_relative "application_record"'? - PullRequest
0 голосов
/ 28 апреля 2019

Исходя из фона Python / Django, я читаю учебник https://guides.rubyonrails.org/getting_started.html. В примере проекта есть каталог app/models с этими файлами,

app/models
├── application_record.rb
└── article.rb

, где article.rb содержит

class Article < ApplicationRecord
end

и application_record.rb

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

После этого ответа я бы ожидал, что article.rb будет иметь

require_relative "application_record"

вверху файла, чтобы получить доступ к классу ApplicationRecord. Почему это не требуется в примере проекта рельсов?

1 Ответ

3 голосов
/ 29 апреля 2019

Главное, что нужно понять, это то, что импорт (необходимый) в 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...