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?
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
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
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
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) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With