#ruby-on-rails-3 #activerecord
#ruby-on-rails-3 #activerecord
Вопрос:
Я хочу отобразить список выбора подклассов MyModel в представлении. Это пока не работает, поэтому для проверки работоспособности я включил это в свое представление:
<%= MyModel.descendants %>
В первый раз, когда я визуализирую эту страницу после повторного запуска сервера, на ней отображается список потомков (их шесть). Все последующие разы это отображается как пустой список []
.
Черт возьми, у меня есть require
инструкция в моих инициализаторах:
Dir[Rails.root.join("app/models/my_models/**/*.rb").to_s].each {|f| require f}
… и я убедился, что они становятся обязательными.
Что за @($%amp; происходит?
Ответ №1:
У меня была та же проблема. Решил проблему, добавив config/initializers/preload_models.rb
с:
Dir[Rails.root 'app/models/*.rb'].map {|f| File.basename(f, '.*').camelize.constantize }
Надеюсь, это кому-нибудь поможет.
Комментарии:
1. Это также все еще выпадает из памяти через несколько минут, когда только что загружено через инициализатор.
2. Мне кажется, это работает для моделей с пространством имен:
Dir[Rails.root 'app/models/**/*.rb'].map { |f| File.path(f).to_s.sub(Rails.root.to_s '/app/models/', '').chomp('.rb').camelize.constantize if !File.path(f).to_s.include?('/concerns/') }
, хотя я не уверен, означает ли исключение проблем, что модели, которые должны быть загружены, не загружены. В моем текущем случае это не проблема.
Ответ №2:
При использовании require, даже если ваш my_model.rb
компьютер будет перезагружен, ядру не потребуются .rb
файлы ваших подклассов, потому что они уже были загружены. Вам пришлось бы выполнить автозагрузку rails.
По сути, по вашему первому запросу rails автоматически загружается MyModel
из my_model.rb
, что затем требует my_models/sub_model.rb
. SubModel
Класс наследует MyModel
, который заполняет descendants
массив. Однако при ваших следующих запросах rails MyModel
снова загружается автоматически (эй, вы в режиме разработки), что затем требует my_models/sub_model.rb
повторения. Но на этот раз ядро знает, что оно уже загрузило этот файл, и не будет загружать его снова.
Я столкнулся с этой проблемой час назад, что привело меня к вашему сообщению и поиску решения. Что нам нужно, так это rails для автоматической загрузки подклассов при каждом вызове вашего основного класса.
Вот решение :
class MyModel
Dir[File.join(File.dirname(__FILE__),"my_models","*.rb")].each do |f|
MyModels.const_get(File.basename(f,'.rb').classify)
end
end
Эти строки, вероятно, можно было бы поместить за пределы класса. Этого должно быть достаточно (это для меня), если у вас есть файлы только в my_models
, а не в подкаталогах. Если у вас есть некоторые (например MyModels::Car::Ford
, вам может потребоваться поместить такие же материалы в подмодули (в my_models/car.rb
).
Комментарии:
1. 1 за четкое объяснение происходящего — спасибо. К сожалению, мои подклассы имеют «сокращенные» имена, такие как «PGEService» с именами файлов, такими как ‘pge_service.rb’. Я не готов переименовывать свои файлы в ‘p_g_e_service.rb’ — по крайней мере, пока!
2. Ну, если ваши файлы называются PGEService.rb, вы можете просто использовать имя файла (без
.classify
), но я не вижу простого решения, если это все ещеpge_service.rb
… Если, конечно, вы не сделаете что-то вродеs=File.basename(f,'.rb').split('_'); class_name = s.first.upcase s.last.classify; MyModels.const_get(class_name)
. Да, немного некрасиво, я знаю.3. строго говоря, вы ответили на мой вопрос «что происходит». Итак, вы заслуживаете галочки. Я уточнил свой вопрос, но я опубликую его как отдельный вопрос. Вперед!
4. На самом деле я немного изменил код в своей модели, потому что при загрузке подклассов я получу неправильные данные: если я загружаю,
SubModel
когдаMyModel
он не был загружен, Rails находит вclass SubModel < Model
строке, которую ему нужно загрузитьMyModel
, для чего, в свою очередь, требуется файл моей подмодели … бесконечный цикл. Решение состоит в том, чтобы напрямую использовать приведенный выше фрагмент в методе descendants.
Ответ №3:
Я просто включил быструю загрузку в каждой среде:
config.eager_load = true
У меня это работало даже при использовании пространств имен для имен классов.
Комментарии:
1. Я думаю , что это будет выигрышный ответ. Может ли кто-нибудь еще подтвердить, что это работает?
2. Это ложноположительный результат, он будет работать несколько минут, затем выпадет из памяти. С какой бы страницей вы ни использовали эту функцию — просто обновите достаточно, и в конечном итоге
descendants
илиsubclasses
снова начнет возвращаться пустым.