Как заставить Rails загружать плагин * после * кода приложения? - PullRequest
6 голосов
/ 25 июня 2010

Я пытаюсь написать плагин, который определяет модель MongoMapper.Проблема в том, что когда я запускаю script/console, я получаю эту ошибку:

/home/helder/.rvm/gems/ruby-1.8.7-p249/gems/mongo_mapper-0.8.2/lib/mongo_mapper/connection.rb:29:in `` database ': NameError: неинициализированная переменная класса @@ database_name в MongoMapper :: Connection`

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

1 Ответ

10 голосов
/ 13 июля 2010

Я попытаюсь рассмотреть как ошибку, с которой я столкнулся, так и общий вопрос, как указано в заголовке.

Конкретная ошибка

Я выяснил, в чем проблема.Как я уже говорил в комментарии выше, проблема в том, что Rails (2.3.8) при использовании ActiveRecord сначала устанавливает соединение с базой данных, затем загружает гемы, а затем плагины (в этом порядке).Поэтому, если у вас есть какие-либо плагины, которым требуется доступ к базе данных во время их инициализации (то есть внутри init.rb или какого-то другого файла require d плагина), все работает нормально.

Но когдаиспользуя MongoMapper, Rails загружает классы MongoMapper вместе со всеми другими гемами / плагинами, но не устанавливает свое соединение (Rails не делает этого, и плагин тоже не запускает это).В настоящее время рекомендуется для документации MongoDB создать такой инициализатор, как этот:

MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
MongoMapper.database = "#myapp-#{Rails.env}"

if defined?(PhusionPassenger)
   PhusionPassenger.on_event(:starting_worker_process) do |forked|
     MongoMapper.connection.connect_to_master if forked
   end
end

Но так как плагины инициализируются до запуска файлов в config/initializers,если вы попытаетесь определить модель MongoMapper, как только она получит вызов, обращающийся к базе данных (например, вызов метода класса key), BOOM.Вы получаете ошибку, процитированную в вопросе.

Один из способов решить эту проблему - , а не требовать в init.rb файлы, которым нужна база данных, а только добавить их в путь загрузки.(если они не в lib/ или app/models, которые Rails автоматически добавляет к пути загрузки).Таким образом, модели будут автоматически загружаться загрузчиком классов Rails только тогда, когда на них ссылаются, что обычно будет внутри кода вашего приложения.К тому времени соединение с БД уже будет установлено.Конечно, это работает, только если вам действительно не нужно ссылаться на эти классы во время инициализации вашего плагина.В противном случае читайте дальше.

Общий вопрос

Как заставить Rails загружать плагин после кода инициализации?

На вашем плагине init.rb, выбросьте что-нибудь , которое требует ожидания внутри этого блока:

config.after_initialize do
  # require my models
  # do this
  # do that
end

Эта переменная config та же самая, что передана в блок, который передается Rails::Initializer.runвнутри вашего config/environment.rb файла и предоставляется Rails для вашего плагина init.rb без дополнительной оплаты.

Все, что вы поместите в этот блок, будет выполнено (Rails::Initializer#after_initialize) после все загружается и инициализируется, но за до поступают любые запросы. Наслаждайтесь.

...