Почему код необходимо перезагрузить в Rails 3? - PullRequest
5 голосов
/ 15 марта 2011

Я бывший разработчик PHP, изучающий Rails и Sinatra.В PHP при каждом запросе страницы загружаются все необходимые файлы.Если бы я изменил какой-то код и обновил страницу, я мог быть уверен, что код был свежим.

В Rails 3 код контроллера обновляется при каждом запросе.Однако, если я изменю какой-либо код в папке / lib, мне нужно перезапустить сервер, чтобы изменения вступили в силу.

Почему это происходит?Это как-то связано с тем, как устроен Ruby?Делает ли Rails некоторую оптимизацию, чтобы избежать перезагрузки кода при каждом запросе?

Спасибо!

Редактировать: Меня больше всего интересует то, что происходит под капотом.Фреймворки, такие как Rails и Sinatra, выполняют специальное кэширование для классов?Если так, что они делают?Поведение по умолчанию в Ruby, когда весь код перезагружается при каждом запросе?Зачем нам нужны такие инструменты, как дробовик для Синатры (http://sinatra -book.gittr.com / # automatic_code_reloading )?

Ответы [ 2 ]

20 голосов
/ 15 марта 2011

Пока вы находитесь в режиме разработки, вы должны указывать Rails не кэшировать ваши классы, чтобы они каждый раз перезагружались. Это означает, что при каждом запросе классы в основном переопределяются в интерпретаторе rails. Настройка в вашем Rails.root / config / environment / development.rb:

config.cache_classes = false

Классы в вашем lib / dir обычно загружаются через инициализатор и не подпадают под этот параметр.

Когда вы перейдете в производство, вы захотите, чтобы все ваши классы кэшировались, чтобы запросы выполнялись быстрее, а rails будут оптимизировать такие вещи, как области видимости в ваших моделях.

Вы можете поместить что-то в другой инициализатор (например, Rails.root / config / initializers / development_reload.rb), который перезагружает каталог lib при каждом запросе в разработке (или только тех, над которыми вы работаете):

# file development_reload.rb
if Rails.env.development?
  ActionDispatch::Callbacks.after do
    load 'filename_in_lib'
    # or
    Dir.entries("#{Rails.root}/lib").each do |entry|
      load entry if entry =~ /.rb$/
    end
  end
end

Я вызываю «load», чтобы он фактически перезагружал файл, тогда как «require» просто проверял, был ли он загружен, и определял, что он уже есть, поэтому он не перезагружал его. (Я просто собрал все это вместе и не использую его, но Ruby чрезвычайно гибок и позволит вам сделать совсем немного.) Используйте что-то подобное мудро и только в среде разработчиков.

Почему код необходимо перезагрузить в Rails 3?

Ruby - это интерпретируемый язык (JRuby имеет некоторую поддержку для предварительной компиляции, но он все еще интерпретируется). Интерпретация определения классов после инициализации аналогична компиляции php и развертыванию в исполняемом формате (в некоторой степени). Переводчику не приходится постоянно переопределять классы.

Принудительная перезагрузка является оптимизацией для этого типа интерпретируемого языка. (если вы компилируете AOT в php, вам потребуется перезагрузить скомпилированный «байт-код» и после изменений; php по умолчанию использует компиляцию «на лету», чем вы и пользуетесь)

2 голосов
/ 11 апреля 2013

Как насчет более высокого уровня подхода:

    ActionDispatch::Reloader.cleanup!
    ActionDispatch::Reloader.prepare!

Это было взято из Rails / ActiveRecord v3.2.13 - active_record / railtie.rb

Подход с нагрузкой у меня не сработал. Просто выполнение загрузки вызвало странную проблему, из-за которой некоторые валидаторы дважды вызывали у меня.

Чтобы это исправить, я попробовал Object.send (: remove_const, User) перед перезагрузкой User, но затем я потерял своих наблюдателей в этом классе, поэтому я начал гоняться за своим хвостом.

Приведенный выше подход перезагружает все классы, поэтому, возможно, все еще существует лучший подход для правильного удаления отдельного класса из кэша и его перезагрузки ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...