18

背景

我有一个最近更新到 Rails 3.2.1(来自 Rails 3.0.x)的应用程序,并重构了 JS 和 CSS 资产以利用新的资产管道。该应用程序使用 Celadon Cedar 堆栈托管在 Heroku 上。

应用配置

我将特定于应用程序的配置保存在名为 app_config.yml 的 YAML 文件中,并使用初始化程序将其加载到全局 APP_CONFIG 变量中:

# config/initializers/load_app_config.rb

app_config_contents = YAML.load_file("#{Rails.root.to_s}/config/app_config.yml")
app_config_contents["default"] ||= {}
APP_CONFIG = app_config_contents["default"].merge(
                       app_config_contents[Rails.env] || {} ).symbolize_keys

Heroku 上的资产编译

Heroku 支持 Cedar 堆栈中内置的 Rails 资产管道。当您将应用程序推送到 Heroku 时,它会自动调用rake assets:precompile服务器作为部署过程中的一个步骤。但是,它在没有数据库访问或正常 ENV 变量的沙盒环境中执行此操作。

如果允许应用程序在资产预编译期间正常初始化,则会在尝试连接到数据库时抛出错误。这很容易通过将以下内容添加到 application.rb 文件中来解决:

    # Do not load entire app when precompiling assets
    config.assets.initialize_on_precompile = false


我的问题

设置时initialize_on_precompile = false,不会运行任何初始化程序config/initializers/*。我遇到的问题是我需要 APP_CONFIG 变量在资产预编译期间可用。

如何load_app_config.rb在资产编译期间加载而不初始化整个应用程序?我可以对group传递给 Rails::Application.initialize 的参数做些什么吗??

4

5 回答 5

46

Rails 允许您仅在某些组中注册初始化程序,但您需要使用 Railtie API:

# in config/application.rb

module AssetsInitializers
  class Railtie < Rails::Railtie
    initializer "assets_initializers.initialize_rails",
                :group => :assets do |app|
      require "#{Rails.root}/config/initializers/load_config.rb"
    end
  end
end

您无需检查 AppConfig 是否已定义,因为它只会在资产组中运行。

您可以(并且应该)继续使用initialize_on_precompile = false. load_config.rb 初始化程序将在初始化应用程序时运行(因为它在 中config/initializers在不初始化的情况下预编译时(因为上面的代码)。

于 2012-10-03T00:05:29.450 回答
7

一定要查看github 上的asset_sync 。或者我们的 Heroku 开发中心文章在 Heroku 上使用带有 Rails 3.1 的 CDN 资产主机

Heroku 实验室插件最近解决了环境变量的问题,它使您的应用程序的heroku config变量可以在编译期间访问。要启用此功能,请阅读user_env_compile插件。

还。使用asset_sync与让您的应用程序在生产中懒惰地编译资产或直接从您的应用程序服务器预编译的资产提供相当大的性能改进。不过我会这么说。我写的。

  • 使用asset_sync 和S3,您可以预编译资产,这意味着所有资产都可以立即在资产主机/CDN 上提供服务
  • 您只能在预编译时要求 application.rb 中的:assets包,从而在生产中节省内存
  • 您的应用服务器永远不会受到资产请求的影响。你可以花费昂贵的计算时间,你知道的。计算。
  • 最佳实践 HTTP 缓存标头均默认设置
  • 您可以使用一个额外的配置启用自动 gzip 压缩
于 2012-03-07T15:42:27.237 回答
2

这就是我想出的。在需要应用程序配置的资产中,我将这一行放在最开始:

<% require "#{Rails.root}/config/initializers/load_config.rb" unless defined?(AppConfig) %>

...并添加.erb到文件名,这样video_player.js.coffee就变成了video_player.js.coffee.erb. 然后我可以安全地使用AppConfig['somekey']之后。

在资产预编译期间,尽管initialize_on_precompile设置为false,但它会加载应用程序配置,并且只执行一次(这避免了不断的重新定义问题)。

是的,这是一个杂物,但比在资产文件中嵌入配置要好很多倍。

于 2012-02-21T12:35:06.283 回答
1

对于 Heroku,我正在运行 Asset Sync gem 以将我的文件存储在 CDN 上,以避免在 Heroku 中获取静态图像。它工作得很好。我也初始化了 precompile false,但是 Asset Sync 运行它自己的初始化程序,所以你可以把你的代码放进去。 https://github.com/rumblelabs/asset_sync

于 2012-02-11T13:05:43.560 回答
0

尽管在预编译资产时您的初始化程序没有运行,但您仍然应该发现它们在 Rails 正常运行时运行,但是,这将在应用程序的第一次命中而不是在部署步骤中运行。

我不完全确定您遇到的问题是什么,但是如果您遵循 Rails 约定,则部署将按预期工作。

于 2012-02-11T00:12:25.363 回答