Ruby on Rails 3 - Перезагрузка каталога lib для каждого запроса
Я создаю новый движок для приложения rails 3. Как вы можете догадаться, этот движок находится в каталоге lib моего приложения.
Однако у меня есть некоторые проблемы, связанные с его развитием. Действительно, мне нужно перезапустить свой сервер каждый раз, когда я что-то меняю в движке.
Есть ли способ избежать этого?
Могу ли я заставить рельсы полностью перезагрузить каталог lib или конкретный файл и его требования для каждого запроса?
Спасибо за вашу помощь:)
Ответы
Ответ 1
TL; DR
-
поместите это в config/application.rb
config.eager_load_paths += ["#{Rails.root}/lib"]
-
удалить инструкции require
для ваших файлов lib
Go!
Позвольте мне подробно объяснить.
Я не знаю, почему этот ответ принят, поскольку он не помогает с перезагрузкой папки lib по каждому запросу. Сначала я подумал, что он работает для Rails 2, но в этом вопросе четко сказано, что он был для Rails 3, а дата релиза 3.0.0 - до даты ответа.
Другие ответы кажутся чрезмерно сложными или не обеспечивают реального решения.
Я решил немного разобраться, потому что это беспокоило меня, и я даже обнаружил, что у людей есть обходное решение для этого, и это связано с сохранением файлов lib внутри app/models
в разработке, а затем перемещение на /lib
когда сделано. Мы можем сделать лучше, верно?
Мое решение проверено на:
- Rails 3.0.20
- Rails 3.1.12
- Rails 3.2.13
- Rails 4.0.0.rc1
Поместите это в свой config/application.rb
:
# in config/application.rb
config.eager_load_paths += ["#{Rails.root}/lib}"]
Что это! ™
Убедитесь, что вы положили его здесь, так как он не работает, если вы поместите его в config/environments/development.rb
, например.
Убедитесь, что вы удалили все операторы require
для вашего кода /lib
, так как инструкции require
также заставят это решение не работать.
Этот код неявно требует вашего кода, поэтому, если вы выполняете проверки среды (что необязательно), и вместо указанного выше кода вы решили написать что-то вроде этого:
# in config/application.rb
config.eager_load_paths += ["#{Rails.root}/lib"] if Rails.env.development?
вы должны следить за старыми операторами require
, поскольку они все еще требуются во всех средах без разработки, в этом сценарии.
Итак, если вы все еще решите выполнить проверки среды, убедитесь, что вы выполняете обратные проверки для операторов запроса. В противном случае вас укусят!
require "beer_creator" unless Rails.env.development?
Вы можете подумать, что писать полный абзац о чем-то ненужном тоже не нужно, но я думаю, что предупреждение людей о том, что необходимо при выполнении чего-то ненужного, также необходимо.
Если вы хотите узнать больше об этой теме, посмотрите этот небольшой учебник.
Ответ 2
Я не мог заставить любой из вышеперечисленных работать для меня, поэтому я немного выкопал код Rails и придумал следующее:
Новый файл: config/initializers/reload_lib.rb
if Rails.env == "development"
lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"]) do
Rails.application.reload_routes! # or do something better here
end
ActionDispatch::Callbacks.to_prepare do
lib_reloader.execute_if_updated
end
end
Да, я знаю это отвратительно, но это взломать. Возможно, лучший способ вызвать полную перезагрузку, но это работает для меня. Моим конкретным вариантом использования было приложение Rack, смонтированное на маршруте Rails, поэтому мне нужно было его перезагрузить, когда я работал над ним в разработке.
В основном, это то, что он проверяет, изменились ли какие-либо файлы в /lib (измененная метка времени) с момента последней загрузки, а затем вызывает перезагрузку, если они меняются.
Я мог бы также упомянуть, что у меня это в моем config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Что только по умолчанию гарантирует, что все в моем каталоге lib загрузится.
Yays!
Ответ 3
Поскольку мы говорим о Rails, самый простой способ - "потребовать" ваши файлы lib/*.rb, используя " require_dependency". До тех пор, пока файлы controller/helper/etc (.rb в приложении /) используют require_dependency, а не просто требуют перезагрузки, без необходимости делать что-либо напуганное.
Прежде чем я пошел по этому треку, единственным решением, которое работало, было то, что было на hemju.com, но я действительно не хотел, чтобы для взлома скорости ApplicationController для Dev.
Ответ 4
Вы должны добавить
config.autoload_paths += %W(#{config.root}/lib)
для вашего класса Application в config/application.rb
https://rails.lighthouseapp.com/projects/8994/tickets/5218-rails-3-rc-does-not-autoload-from-lib
Ответ 5
В RAILS 3 здесь секретный соус для автоматической перезагрузки файлов lib. Код ниже немного перебор, для примера, но это то, что я сделал, чтобы заставить его работать. Вы можете изменить сообщение в YoYo # gogo и увидеть на экране каждую загрузку страницы. Удалите инициализатор, и он останется тем же.
/config/initializers/lib_reload.rb(новый файл)
ActiveSupport::Dependencies.explicitly_unloadable_constants << 'YoYo'
ActiveSupport::Dependencies.autoload_once_paths.delete(File.expand_path(File.dirname(__FILE__))+'/lib')
/lib/yo_yo.rb
class YoYo
def gogo
"OH HAI THERE"
end
end
/приложение/контроллеры/home_controller
require 'yo_yo'
class HomeController < ApplicationController
def index
@message = YoYo.new.gogo
end
end
Ответ 6
Вот моя версия, вдохновленная ответом @pbhogan, который перезагружает все рубиновые файлы в вашем каталоге rails/lib при изменении любого из этих файлов.
Он также отключает предупреждения, чтобы избежать сообщений относительно уже инициализированных констант.
Работает с Rails 3.2.8
if Rails.env.development?
lib_ruby_files = Dir.glob(File.join("lib/**", "*.rb"))
lib_reloader ||= ActiveSupport::FileUpdateChecker.new(lib_ruby_files) do
lib_ruby_files.each do |lib_file|
silence_warnings { require_dependency(lib_file) }
end
end
ActionDispatch::Callbacks.to_prepare do
lib_reloader.execute_if_updated
end
end
Ответ 7
Обновленный ответ
Я подытоживаю все свои выводы в своем блоге, вы можете посмотреть там:
Старый ответ
Я искал решение для этого тоже, и (для полноты, а также для указания других в этом направлении) вот что я нашел.
С Rails3.1 двигатели могут быть легко сгенерированы с помощью команды rails plugin new my_plugin --full
. Это создает скелет для двигателя.
--full
означает, что движок будет "слит" прямо во включенное приложение, так что, например, контроллеры должны быть доступны напрямую, как если бы они были определены в приложении, включенном в приложение. Это позволяет вам, например, иметь вспомогательный файл в my_engine/app/helpers/my_helper.rb
, который будет объединен прямо в ваше приложение app/helpers/my_helper.rb helper
.
Есть еще одна опция --mountable
, которая создает пространство имен для движка, чтобы его контроллеры и т.д. никогда не сталкивались с включенными приложениями. Это приводит к, например, хелпер находится в my_engine/app/helpers/my_engine/my_helper.rb
, который не столкнется с помощником app/helpers/my_helper.rb
в вашем включенном приложении.
Теперь более интересная часть:
В сгенерированной рабочей папке test
есть папка dummy
, которая содержит полное приложение Rails! Для чего это?
Когда вы разрабатываете движок, его функциональные возможности предназначены для самостоятельной работы, и он также должен быть полностью протестирован сам по себе. Таким образом, это "неправильный" способ разработки движка "внутри" другого приложения Rails (хотя он интуитивно часто будет чувствовать себя правильно при извлечении существующих функций из приложения Rails в движок), и поэтому теоретически также не нужно перезагружать движок кода с каждым запросом к включенному приложению.
"Правильный" способ, похоже, таков: разработать и протестировать ваш движок, как если бы это было полное приложение Rails с помощью приложения dummy
! В этом вы можете сделать все, что вы можете сделать в любом "обычном" Rails-приложении, например. создавать контроллеры, модели, представления и т.д., которые используют функциональные возможности, которые должен обеспечить движок. Обычно вы можете запускать сервер с помощью rails s
в каталоге test/dummy
и обращаться к фиктивному приложению на localhost:3000
, а при выполнении тестов приложение dummy
автоматически используется для тестов интеграции. Довольно мило!: -)
Вы должны быть осторожны, где разместить свои вещи:
- Любая функциональность, предназначенная для использования в другом приложении Rails, переходит в
my_engine/app
, тогда как любая функция, которая требуется только для проверки функциональности движка, переходит в test/dummy/app
.
Затем вы можете легко загрузить свой движок в основное приложение Gemfile
следующим образом: gem 'my_engine', :path => 'path/to/my_engine'
или опубликовать его в GitHub как драгоценный камень.
(Одна интересная вещь (и вернуться к этой теме) заключается в том, что когда я запускаю фиктивный сервер, все изменения в движке кажутся отраженными внутри него! Итак, как-то кажется возможным включить движок в приложении Rails без кэширования...? Я не знаю, как это происходит.)
Итак, чтобы подвести итог: двигатель обеспечивает функциональность, которая может полностью стоять сама по себе, поэтому ее также следует разрабатывать и тестировать самостоятельно. Затем, когда он достиг стабильного состояния, он может быть включен любым другим приложением, которое нуждается в его функциональности.
Здесь некоторые ресурсы, которые я нахожу полезными:
Надеюсь, вы найдете этот ответ полезным. Я все еще очень новичок в машинах в целом, поэтому, если есть какая-то неправильная информация, скажите, пожалуйста, и я ее исправлю.
Ответ 8
Добавьте в application_controller.rb
или ваш базовый контроллер:
before_filter :dev_reload if Rails.env.eql? 'development'
def dev_reload
# add lib files here
["rest_client.rb"].each do |lib_file|
ActiveSupport::Dependencies.load_file lib_file
end
end
Работал для меня.
Ответ 9
обратите внимание, что в Rails 3 "load_once_paths" становится "autoload_once_paths."
Кроме того, кажется, что он должен быть пустым, если вы явно не помещаете в него что-либо.
Ответ 10
Кроме того, убедитесь, что вы закомментируете следующую строку в application.rb(в дополнение к решению @dishod) и убедитесь, что имя вашего модуля совпадает с именем вашего файла (иначе рельсы не смогут чтобы найти его)
#Dir.glob("./lib/*.{rb}").each { |file| require file } # require each file from lib directory
Ответ 11
Работает для Rails 3.2.13 для перезагрузки lib внутри gem приложения:
require_dependency 'the_class'
и
config.autoload_paths + =% W (# {config.root}/../fantasy/lib)