在 Heroku 上预编译资产时如何普遍跳过数据库操作

发布于 2024-12-04 14:43:28 字数 874 浏览 0 评论 0原文

我正在将 Rails 3.1 应用程序部署到 Heroku 的 Cedar 堆栈。使用 Heroku Cedar 和 Rails 3.1,您可以在本地自己编译资产,让 Heroku 在您推送时编译它们(在“slug”期间)编译”),或者在应用程序运行时即时编译它们。我想做中间选项,让 Heroku 预编译资产。

当 Heroku 运行 asset:precompile 任务时,会出现错误 “无法连接到服务器”,因为应用程序正在尝试连接到数据库,但在 slug 编译的该阶段没有可用的数据库。此时缺少数据库连接是预料之中且不可避免的。我正在寻找一种方法来克服它,因为数据库连接对于资产预编译并不重要。

我的应用程序中尝试连接到数据库的部分是 Devise。 routes.rb 中有一个 devise_for :users 行想要查看 User 模型。

我可以编写一个 rake 任务来删除 devise_for 并将其作为 asset:precompile 的先决条件。我认为这可以解决我的问题,但是我正在寻找一种更通用的解决方案,我可以在 Heroku 上出现此问题的任何 Rails 3.1 应用程序上使用它。

有没有什么东西,或者您能想到什么东西可以消除数据库连接错误,同时仍然运行应用程序足以生成路线和资产路径?

显然,如果应用程序需要在启动期间读取/写入数据,我们无法对其进行存根,但是我们可以自动伪造每个 ActiveRecord 模型吗?

I'm deploying a Rails 3.1 app to Heroku's Cedar stack. With Heroku Cedar and Rails 3.1, you can compile the assets yourself locally, let Heroku compile them when you push (during "slug compilation"), or have them be compiled just-in-time while the app is running. I want to do the middle option, letting Heroku precompile the assets.

When Heroku runs the assets:precompile task, it errors with "could not connect to server" because the app is trying to connect to the database but no database is available at that stage of slug compilation. The lack of database connection is expected and unavoidable at this point. I'm looking for a way to move past it, because a database connection isn't crucial to asset precompilation.

The part of my app that's trying to connect to the database is Devise. There's a devise_for :users line in routes.rb that wants to look at the User model.

I could just write a rake task that stubs out devise_for and make it a prereq of assets:precompile. I think that would solve my problem, but I'm looking for a more universal solution that I could use on any Rails 3.1 app with this problem on Heroku.

Is there anything out there, or can you conceive of anything that silences database connection errors while still running the app enough to have route and asset path generation?

Obviously if an app needs to read/write data during startup, we can't stub that, but can we fake every ActiveRecord model automatically?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

梦归所梦 2024-12-11 14:43:28

将其添加到 config/application.rb

config.assets.initialize_on_precompile=false                                                  

花了我一段时间才找到它...将其添加到 config/environments/*.rb 不起作用

更新:它不适用于 Rails 4

add this to config/application.rb

config.assets.initialize_on_precompile=false                                                  

took me a while to hunt this down... adding it to config/environments/*.rb did NOT work

UPDATE: It doesn't work with rails 4

乖乖兔^ω^ 2024-12-11 14:43:28

Heroku 现在提供了一个 labs 标志,这将使运行时环境在编译期间可用,这意味着您的应用将能够成功连接到您的 DATABASE_URL 数据库。

首先,您需要安装 labs 插件:

$ heroku plugins:install http://github.com/heroku/heroku-labs.git

然后启用 user-env-compile 实验室功能

$ heroku labs:enable user-env-compile --app your-app-name

Heroku now makes a labs flag available that'll make the runtime environment available during compilation time, which means your app will be able to successfully connect to your DATABASE_URL database.

First you need to install the labs plugin:

$ heroku plugins:install http://github.com/heroku/heroku-labs.git

then enable the user-env-compile labs feature:

$ heroku labs:enable user-env-compile --app your-app-name
请远离我 2024-12-11 14:43:28

对我来说,问题是 activerecord 在 lib/active_record/railtie.rb:92 中调用 instantiate_observer 。这将加载观察者和相应的模型。 has_and_belongs_to_many 然后连接到数据库。

我想当 ENV["RAILS_ASSETS_PRECOMPILE"] 存在时我会重写此方法,该方法由 Bradley 链接到的修复程序中的 devise 使用。

编辑:所以这个片段为我修复了它:

namespace :assets do
  # Prepend the assets:precompile_prepare task to assets:precompile.
  task :precompile => :precompile_prepare

  # This task will be called before assets:precompile to optimize the
  # compilation, i.e. to prevent any DB calls.
  task 'precompile_prepare' do
    # Without this assets:precompile will call itself again with this var set.
    # This basically speeds things up.
    ENV['RAILS_GROUPS'] = 'assets'

    # Devise uses this flag to prevent connecting to the db.
    ENV['RAILS_ASSETS_PRECOMPILE'] = 'true'

    # Prevent loading observers which will load the models which in turn may hit
    # the DB.
    module ActiveModel::Observing::ClassMethods
      def instantiate_observers; end
    end

    # Prevent route drawing because certain gems might get called which will hit
    # the DB.
    class ActionDispatch::Routing::RouteSet
      def draw; end
    end
  end
end

For me the problem is activerecord calling instantiate_observer in lib/active_record/railtie.rb:92. This will load the observers and the respective models. has_and_belongs_to_many then connects to the db.

I think I'll override this method when ENV["RAILS_ASSETS_PRECOMPILE"] is present, which is used by devise in the fix Bradley linked to.

EDIT: So this snippet fixed it for me:

namespace :assets do
  # Prepend the assets:precompile_prepare task to assets:precompile.
  task :precompile => :precompile_prepare

  # This task will be called before assets:precompile to optimize the
  # compilation, i.e. to prevent any DB calls.
  task 'precompile_prepare' do
    # Without this assets:precompile will call itself again with this var set.
    # This basically speeds things up.
    ENV['RAILS_GROUPS'] = 'assets'

    # Devise uses this flag to prevent connecting to the db.
    ENV['RAILS_ASSETS_PRECOMPILE'] = 'true'

    # Prevent loading observers which will load the models which in turn may hit
    # the DB.
    module ActiveModel::Observing::ClassMethods
      def instantiate_observers; end
    end

    # Prevent route drawing because certain gems might get called which will hit
    # the DB.
    class ActionDispatch::Routing::RouteSet
      def draw; end
    end
  end
end
烈酒灼喉 2024-12-11 14:43:28

Rails(4.2 Edge)的解决方法:

将以下内容添加为 /config/initializers/precompile.rb

module Precompile

  # Public: ignore the following block during rake assets:precompile
  def self.ignore

    unless ARGV.any? { |e| e == 'assets:precompile' }
      yield
    else
      line = caller.first
      puts "Ignoring line '#{line}' during precompile"
    end

  end

end

并在 routes.rb 中使用它,如下所示:

Precompile.ignore { ActiveAdmin.routes(self) }

Workaround for Rails (4.2 edge):

Add the following as /config/initializers/precompile.rb:

module Precompile

  # Public: ignore the following block during rake assets:precompile
  def self.ignore

    unless ARGV.any? { |e| e == 'assets:precompile' }
      yield
    else
      line = caller.first
      puts "Ignoring line '#{line}' during precompile"
    end

  end

end

and use it in your routes.rb like this:

Precompile.ignore { ActiveAdmin.routes(self) }
浅沫记忆 2024-12-11 14:43:28

编辑:这个答案已经过时,不再有效 - 请参阅 fringd 的答案。

不完全是通用存根,但设计现在添加了一个检查来解决这个特定问题。请参阅问题修复 在 Github 上。通过提供 RAILS_ASSETS_PRECOMPILE 环境配置设备应该跳过构建路由

EDIT: This answer is out of date and no longer works - See fringd's answer.

Not quite a universal stubbing but devise has added a check now to fix this particular problem . See the issue and fix on Github. By providing a RAILS_ASSETS_PRECOMPILE environment config devise should skip building the routes

恋竹姑娘 2024-12-11 14:43:28

我将其放在“lib/tasks/assets.rake”中,并且能够获得资产:预编译真正成功。只要您不因需要您的环境而实际访问数据库,这应该就可以工作。它显然对 ActiveRecord 没有帮助,但它应该适用于所有基于 mongoid 的应用程序。

task 'assets:precompile' => 'assets:stub_mongoid'

task 'assets:stub_mongoid' do
  def Mongoid.load!(*args)
    true
  end
end

I stuck this in 'lib/tasks/assets.rake' and was able to get assets:precompile to actually succeed. This should work as long as you don't actually access the database as a result of requiring your environment. It obviously won't help with ActiveRecord, but it should work for all mongoid-based apps.

task 'assets:precompile' => 'assets:stub_mongoid'

task 'assets:stub_mongoid' do
  def Mongoid.load!(*args)
    true
  end
end
上课铃就是安魂曲 2024-12-11 14:43:28

Heroku 添加了一个非官方标志,以使环境(即数据库)在预编译期间可访问。只需要求他们将其打开,资产预编译期间的数据库依赖性就不再是问题。不确定该标志是否/何时正式可用,或者它是否只是新的默认值。

Heroku added an unofficial flag to make the environment (i.e. also the DB) accessible during precompilation. Just ask them to switch it on and DB dependencies during asset precompilations are no longer an issue. Not sure, if/when this flag is officially available though, or if it will simply be the new default.

ぶ宁プ宁ぶ 2024-12-11 14:43:28

Spork.trap_method也是一个有趣的解决方案,解决了Devise的routes_for在加载过程早期调用模型的问题。 AFAIK 解决方案不能直接应用,但它正在解决同一类型的问题,因此它可能会为某人提供灵感。

Spork.trap_method

Spork.trap_method is also an interesting solution to the problem of Devise's routes_for calling the model early in the load process. Solution can't be applied directly AFAIK, but it's solving the same sort of problem, so it might provide inspiration for somebody.

Spork.trap_method

夏末的微笑 2024-12-11 14:43:28

我缺乏足够的声誉来发表评论,所以这是另一个答案。

确实,@fringd 的顶级答案在 Rails 4 上不起作用。但是,我发现这种技术可以工作:

https://iprog.com/posting/2013/07/errors-when-precompiling-assets-in-rails-4-0

尽管如此,我重新排列了 BASH 变量,如下所示:

~$ RAILS_ENV=production DATABASE_URL=postgresql://user:[email protected]/dbname bundle exec rake assets:precompile

顺便说一句如果您需要构建 Docker 映像,这是一个极好的帮助。将该行放入您的 Dockerfile 中,以便您的数据库可以驻留在不同的容器中,并且您的应用程序容器不需要在每次启动时预编译资产!

I lack sufficient reputation to comment, so here's another answer.

It's true that @fringd's top-rated answer does not work on Rails 4. I have, however, found this technique to work:

https://iprog.com/posting/2013/07/errors-when-precompiling-assets-in-rails-4-0

Although, I rearranged the BASH variables like so:

~$ RAILS_ENV=production DATABASE_URL=postgresql://user:[email protected]/dbname bundle exec rake assets:precompile

BTW, This is a fantastic aid if you need to build a Docker image. Put that line into your Dockerfile so your DB can live in a different container and your app containers don't need to precompile assets every time they start up!

不醒的梦 2024-12-11 14:43:28

禁用增强现实:

config = Rails.application.config
def config.database_configuration
  {}
end

ar = ActiveRecord::Base
def ar.establish_connection
end

Disable AR:

config = Rails.application.config
def config.database_configuration
  {}
end

ar = ActiveRecord::Base
def ar.establish_connection
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文