如何让 Rails 在应用程序代码*之后*加载插件?
我正在尝试编写一个定义 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: uninitialized class variable @@database_name in MongoMapper::Connection`
这让我认为它在设置数据库连接之前尝试加载我的插件模型。如何让它在应用程序代码的其余部分之后加载插件?
I'm trying to write a plugin that defines a MongoMapper model. The problem is that when I run script/console
, I get this error:
/home/helder/.rvm/gems/ruby-1.8.7-p249/gems/mongo_mapper-0.8.2/lib/mongo_mapper/connection.rb:29:in
``database':NameError: uninitialized class variable @@database_name in MongoMapper::Connection`
which leads me to think that it's trying to load my plugin model before setting up the database connection. How do I make it load the plugin after the rest of my application code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我将尝试解决我遇到的错误以及标题中所述的一般问题。
具体错误
我弄清楚是什么问题了。正如我在上面的评论中所说,问题是Rails(2.3.8)在使用ActiveRecord时,首先设置数据库连接,然后加载gems,然后加载插件(按此顺序)。因此,如果您有任何插件需要在初始化期间访问数据库(即在插件的
init.rb
或该插件所需的其他文件require
内),一切正常。但是当使用 MongoMapper 时,Rails 会加载 MongoMapper 的类以及所有其他 gem/插件,但不会建立其连接(Rails 不会这样做,并且插件本身也不会触发该连接) )。 MongoDB 文档目前推荐的方法是创建一个像这样的初始化器:
但是由于插件是在运行 config/initializers 中的文件之前初始化的,如果您尝试定义 MongoMapper 模型,一旦它调用访问数据库(就像调用
key
类方法),BOOM。您收到问题中引用的错误。解决此问题的一种方法是在
init.rb
中不需要需要数据库的文件,而只是将它们添加到加载路径中(如果它们不在lib/
或app/models
,Rails 自动添加到加载路径)。这样,只有在引用模型时,Rails 的自动类加载器才会需要
模型,这通常位于应用程序代码中。到那时,数据库连接就已经建立了。当然,只有当您确实不需要在插件初始化期间引用这些类时,这才有效。否则,请继续阅读。一般问题
如何让 Rails 在初始化代码之后加载插件?
在插件的
init.rb
上,抛出任何东西 需要在此块内等待:该
config
变量与传递给config/ 内的
文件,并且由 Rails 提供给您的插件的Rails::Initializer.run
的块相同environment.rbinit.rb
,无需额外费用。您放入该块中的任何内容都将被执行(通过
Rails::Initializer# after_initialize
)之后一切都完成加载并初始化,但之前任何请求进来。享受吧。I will try to address both the error I encountered as well as the general question as stated in the title.
The specific error
I figured out what the problem was. As I said in a comment above, the problem is that Rails (2.3.8), when using ActiveRecord, first sets up the database connection, then loads gems, then plugins (in this order). So if you have any plugins that need to access the database during their initialization (that is, inside the plugin's
init.rb
or some other filerequire
d by this one), everything works fine.But when using MongoMapper, Rails loads MongoMapper's classes together with all other gems/plugins, but doesn't set up its connection (Rails doesn't do it, and the plugin doesn't trigger that itself either). The way currently recommended on MongoDB's documentation is to create an initializer like this:
But since plugins are initialized before files in
config/initializers
are run, if you try to define a MongoMapper model, as soon as it gets to a call that access the database (like a call to thekey
class method), BOOM. You get the error quoted in the question.One way to solve this is to not require in
init.rb
the files that need the database, but rather only add them to the load path (if they're not inlib/
orapp/models
, which Rails automatically adds to the load path). That way, the models will only berequire
d by Rails' auto class loader when they are referenced, which will usually be inside your application code. By then, the db connection will already be set up. Of course, this only works if you indeed don't need to reference these classes during your plugin's initialization. Otherwise, read on.The general question
How to make Rails load a plugin after the initialization code?
On your plugin's
init.rb
, throw anything that needs waiting inside this block:That
config
variable is the same passed to the block which is passed toRails::Initializer.run
inside yourconfig/environment.rb
file, and is made available to your plugin'sinit.rb
by Rails at no extra cost.Anything you put inside that block will be executed (by
Rails::Initializer#after_initialize
) after everything is finished loading and getting initialized, but before any requests come in. Enjoy.