在Rails 3中运行时加载gem

时间:2022-01-22 00:22:00

I have Rails 3.0.x application. I would like to load gems on runtime, without using Gemfile.

我有Rails 3.0.x应用程序。我想在运行时加载gem,而不使用Gemfile。

What I would like to accomplish is to load my application as usual, with regular gems being loaded by Bundler. After that I would like to load all gems (Rails Engines) located in a specific directory (but until runtime, I don't know what gems will that be).

我想要完成的是像往常一样加载我的应用程序,由Bundler加载常规gem。之后我想加载位于特定目录中的所有gem(Rails Engines)(但直到运行时,我不知道那将是什么宝石)。

Does anybody know if this is possible in Rails, maybe using Bundler API?

有人知道这是否可以在Rails中使用,也许使用Bundler API?

2 个解决方案

#1


6  

What you're trying to do is dangerous. If each of your Rails Engines are also gems - then they would also have Gemfiles with other dependencies, and those would in turn have other dependencies, etc. If you allow Bundler to resolve those, then you would have lesser problems at runtime.

你要做的是危险的。如果你的每个Rails引擎都是宝石 - 那么它们也会有Gemfiles和其他依赖项,而这些依赖项还有其他依赖项等。如果你允许Bundler解决这些问题,那么你在运行时会遇到较少的问题。

Here's how you would do it without any hacks. Remember that your Gemfile is just Ruby code, and you can have gems which are not loaded by default.

这是你如何做到没有任何黑客攻击。请记住,您的Gemfile只是Ruby代码,您可以拥有默认情况下未加载的gem。

# In your Gemfile, add at the end:
Dir[YOUR_RAILS_ENGINES_SUBFOLDER + "/*/*.gemspec"].each do |gemspec_file|
  dir_name = File.dirname(gemspec_file)
  gem_name = File.basename(gemspec_file, File.extname(gemspec_file))

  # sometimes "-" and "_" are used interchangeably in gems
  # for e.g. gemspec_file is "engines/my-engine/my_engine.gemspec"
  #   dir_name will be engines/my-engine
  #   gem_name will be my_engine

  # Register that engine as a dependency, *without* being required
  gem gem_name, :path => dir_name, :require => false

  # e.g. this is similar to saying
  #  gem 'my_engine', :path => 'engines/my-engine', :require => false
end

Now you have all your dynamic Rails engines registered as gem dependencies. Bundler will resolve them, and all their sub-dependencies, so you don't have to worry about anything. Just run bundle install once before running the application, or whenever you add/remove any engine in that folder.

现在,您已将所有动态Rails引擎注册为gem依赖项。 Bundler将解决它们及其所有子依赖关系,因此您不必担心任何事情。只需在运行应用程序之前运行一次bundle install,或者在您添加/删除该文件夹中的任何引擎时运行。

The good thing is, these gems will just be registered, and not loaded. So in your production code, you can now load whatever gem that you choose at runtime simply by saying require <your-engine-name>

好消息是,这些宝石只会被注册,而不会被加载。因此,在您的生产代码中,您现在可以通过说出require 来加载您在运行时选择的任何gem

Edit: Extra code comments

编辑:额外代码评论

#2


0  

Try this:

尝试这个:

Bundler.with_clean_env do
  # require gems...
end

#1


6  

What you're trying to do is dangerous. If each of your Rails Engines are also gems - then they would also have Gemfiles with other dependencies, and those would in turn have other dependencies, etc. If you allow Bundler to resolve those, then you would have lesser problems at runtime.

你要做的是危险的。如果你的每个Rails引擎都是宝石 - 那么它们也会有Gemfiles和其他依赖项,而这些依赖项还有其他依赖项等。如果你允许Bundler解决这些问题,那么你在运行时会遇到较少的问题。

Here's how you would do it without any hacks. Remember that your Gemfile is just Ruby code, and you can have gems which are not loaded by default.

这是你如何做到没有任何黑客攻击。请记住,您的Gemfile只是Ruby代码,您可以拥有默认情况下未加载的gem。

# In your Gemfile, add at the end:
Dir[YOUR_RAILS_ENGINES_SUBFOLDER + "/*/*.gemspec"].each do |gemspec_file|
  dir_name = File.dirname(gemspec_file)
  gem_name = File.basename(gemspec_file, File.extname(gemspec_file))

  # sometimes "-" and "_" are used interchangeably in gems
  # for e.g. gemspec_file is "engines/my-engine/my_engine.gemspec"
  #   dir_name will be engines/my-engine
  #   gem_name will be my_engine

  # Register that engine as a dependency, *without* being required
  gem gem_name, :path => dir_name, :require => false

  # e.g. this is similar to saying
  #  gem 'my_engine', :path => 'engines/my-engine', :require => false
end

Now you have all your dynamic Rails engines registered as gem dependencies. Bundler will resolve them, and all their sub-dependencies, so you don't have to worry about anything. Just run bundle install once before running the application, or whenever you add/remove any engine in that folder.

现在,您已将所有动态Rails引擎注册为gem依赖项。 Bundler将解决它们及其所有子依赖关系,因此您不必担心任何事情。只需在运行应用程序之前运行一次bundle install,或者在您添加/删除该文件夹中的任何引擎时运行。

The good thing is, these gems will just be registered, and not loaded. So in your production code, you can now load whatever gem that you choose at runtime simply by saying require <your-engine-name>

好消息是,这些宝石只会被注册,而不会被加载。因此,在您的生产代码中,您现在可以通过说出require 来加载您在运行时选择的任何gem

Edit: Extra code comments

编辑:额外代码评论

#2


0  

Try this:

尝试这个:

Bundler.with_clean_env do
  # require gems...
end