Speed up Heroku deploy for Rails 4 app - heroku

Is there a way to cache precompiled assets for a Rails 4 app on Heroku?
I followed the instructions from this blog post and some of the heroku docs, which sped things up considerdably, but still taking just as long to precompile assets.
Here's the relevant section from my gemfile (also found it necessary to enable the 'user-env-compile' lab):
group :production, :staging do
# for heroku, see https://devcenter.heroku.com/articles/rails-integration-gems
gem 'rails_12factor'
# https://devcenter.heroku.com/articles/rack-cache-memcached-rails31
gem 'rack-cache'
gem 'kgio'
# faster heroku deploys (http://blog.alexmaccaw.com/faster-deploys)
gem 'memcachier'
gem 'dalli'
end
And from my config/production.rb and config/staging.rb:
# Neither of the below worked (tried separately)
# config.assets.cache_store = :dalli_store
config.assets.configure {|env| env.cache = ActiveSupport::Cache.lookup_store(:dalli_store) }
Thanks!

Take a look at the assets_sync gem.

Related

Why did Rails4 drop support for "assets" group in the Gemfile

In Rails 3, gems used exclusively to generate assets in the asset pipeline were properly placed in the assets group of the Gemfile:
...
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'sass-rails'
gem 'coffee-rails'
gem 'uglifier'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', :platforms => :ruby
end
Now, according to the (still in progress) upgrade documentation:
Rails 4.0 removed the assets group from Gemfile. You'd need to remove that line from your Gemfile when upgrading.
Sure enough, making a new project with RC1 yields a Gemfile with asset-related gems included by default outside of any group:
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.0.rc1'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0.rc1'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
...
Does this mean these gems will now be bundled in production builds by default? If so, why the change of heart? Is Rails 4 moving towards the dynamic generation of assets in production?
Previously the assets group existed to avoid unintended compilation-on-demand in production. As Rails 4 doesn't behave like that anymore, it made sense to remove the asset group.
This is explained in more detail in the commit that changed that. I extracted some quotes with the actual answer.
Some gems can be needed (in production) like coffee-rails if you are using coffee templates
and the fact that now assets are not precompiled on demand in production anymore.
(not precompiled on demand in production) Means that if you have that gems in production environment in 3.2.x and forget to precompile, Rails will do exactly what it does in development, precompile the assets that was requested. This is not true anymore in Rails 4, so if you don't precompile the assets using the tasks you will get a 404 when the assets are requests.
Rails 4 try to force you to precompile your assets before deployment. You have to precompile your assets with
$ RAILS_ENV=production bundle exec rake assets:precompile
And why?
I found this in Guide:
By default Rails assumes that assets have been precompiled and will be
served as static assets by your web server.
(Source: http://edgeguides.rubyonrails.org/asset_pipeline.html#in-production)
But many time you have to use these 'assets' gems in production... for example, if you use a js.coffee file in your views directory, then Rails needs coffee compiler in production mode as well.
So I guess, the reason of this change is performance improvement... and looks more simple as well. :)
We want coffeescript with AJAX (history), so coffee-rails moves out of the assets group.
sass-rails misbehaves (history), so it moves out of the assets group.
Axe the assets group.

Error syncing .less files when I push to Heroku app using asset_sync gem?

I have a Rails 3.2.12 app and I was trying to sync my assets using an Amazon S3 bucket and the asset_sync gem for my Heroku app.
I've looked on the whole github issues tracker and here on SO, but wasn't able to find an answer to this. So here's my question:
Is it possible to sync .less files using the asset_sync gem?
After I push to Heroku, I get in the logs this error:
Running: rake assets:precompile
rake aborted!
variable #inputHeight is undefined
(in /tmp/build_tejom7tf9zq9/app/assets/stylesheets/utils-and-mixins.less)
In order to config my app I followed the wiki from the asset_sync github page and to set my ENV variables I used the Built-in Initializer.
Here are the modifications in my production.rb file in order to fit the asset_sync requirements:
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += [ '*.css' ]
# Serving Assets From S3 on Heroku
config.action_controller.asset_host = "//s3.amazonaws.com/test"
# store assets in a 'folder' instead of bucket root
config.assets.prefix = "/production/assets"
end
Any suggestion would be highly appreciated. Thank you
Edit 1:
I tried even running separately in my command line:
heroku run rake assets:precompile --app <yourapp>
but it didn't help, it threw the same error.
Edit 2:
I guess this is what you asked for:
....
gem 'less-rails', '~> 2.3.2'
gem 'twitter-bootstrap-rails', '2.2.6'
# Gems used only for assets and not required in production environments by default.
group :assets do
gem 'sass-rails', '~> 3.2.3'
gem 'coffee-rails', '~> 3.2.1'
gem 'uglifier', '>= 1.0.3'
gem 'therubyracer', '~> 0.11.4', platforms: :ruby
gem 'asset_sync'
end
Managed to make it work by writing in my production.rb the specific .css file names that I wanted to include to my S3 bucket:
# Enable serving of images, stylesheets, and JavaScripts from an asset server
config.action_controller.asset_host = "//s3.amazonaws.com/test"
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += %w( public.css users.css admin.css )

Gemfile - separating Production gems from Development gems

So I know that in a Gemfile I can do something like this:
group :development, :test do
gem 'gem1'
gem 'gem2'
end
What I am looking to accomplish is something like this:
group :production do
gem 'gem1'
gem 'gem2'
end
group :development, :test do
gem 'gem1', :path => '/Documents/Code/gem1/'
gem 'gem2', :path => '/Documents/Code/gem2/'
end
So our application uses 2 gems that we also develop locally. In order to improve time while developing on our local machines, we want to be able to point our dev environments to the local copies of the gems - this way it picks up all changes without needing to restart our rails server. Otherwise we would have to rebuild the gem, re-install the gem, and restart rails with every development change in the gem.
However, doing this gives me the following error:
You cannot specify the same gem twice coming from different sources. You specified that gem1 (>= 0) should come from an unspecfied source and source at /Documents/Code/gem1
I have tried even running something like bundle install --without production and I get the same error.
Does anyone know if it IS possible to do what I would like to do?
Thanks!
i think that there is a supported way to do it and some hacks to work around it.
supported way:
use bundle config with the local option as described here: http://bundler.io/v1.3/man/bundle-config.1.html
hacky way:
use env vars and execute bundler before using in production: http://www.cowboycoded.com/2010/08/10/using-2-sources-for-a-gem-in-different-environments-with-bundler/
there is a feature-request for this problem on github with several related issues and lots of comments: https://github.com/carlhuda/bundler/issues/396
the github issue phoet linked to is resolved, and is consistent with the supported way.
I dug around through the docs, you'll need to set the config variable and updated your gemfile to reference the branch as well.
e.g.
edit your Gemfile:
gem <gem_name>, git: <git_url>, branch: <branch>
on command line:
bundle config local.<gem_name> <local_path_to_gem>
I solved this by creating a new Gemfile that's identical to the original except for the target gem's source. Then, in config/boot.rb, I used:
require 'rails'
if Rails.env.development?
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../DevGemfile', __FILE__)
else
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../ProdGemfile', __FILE__)
end

Sinatra + Heroku + Datamapper deploy issues with dm-sqlite-adapter

For some reason, heroku tries to require dm-sqlite-adapter, even though it should use Postgres here. Note, that this happens when I open any URL - not during the git push itself.
I built a default facebook app.
The Gemfile:
source :gemcutter
gem "foreman"
gem "sinatra"
gem "mogli"
gem "json"
gem "httparty"
gem "thin"
gem "data_mapper"
gem "heroku"
group :production do
gem "pg"
gem "dm-postgres-adapter"
end
group :development, :test do
gem "sqlite3"
gem "dm-sqlite-adapter"
end
Datamapper setup:
# Setting up the database
DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/data/mydatabase.db")
Relevant log fragment, when any URL is opened:
Starting process with command `bundle exec thin -R config.ru start -p 34984`
2012-01-18T15:11:55+00:00 app[web.1]: /app/vendor/bundle/ruby/1.9.1/gems/dm-core-1.2.0/lib/dm-core/adapters.rb:163:in `require': no such file to load -- dm-sqlite-adapter (LoadError)
2012-01-18T15:11:55+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/dm-core-1.2.0/lib/dm-core/adapters.rb:163:in `load_adapter'
Tried related solutions, but with no help so far.
BTW: bundle install says Using do_postgres and Using dm-postgres-adapter. Am I missing something about Datamapper setup?
Well, too many Rails apps on Heroku, I took the shared db presence for granted. heroku config showed neither DATABASE_URL or SHARED_DATABASE_URL set.
Issuing heroku addons:add shared-database:5mb solved the problem.
Strange, that the db wasn't automatically added, despite having 'pg' gem in Gemfile.
Quote from http://devcenter.heroku.com/articles/cedar:
A Heroku shared PostgreSQL database (shared-database:5mb) will be
automatically added to your app in any of the following cases:
The app is a Rails application
The pg gem is specified in the Gemfile
Try doing DataMapper.setup(:default, ENV['DATABASE_URL'] || 'postgres://user:password#hostname/data/mydatabase.db') instead. Heroku is probably looking at the protocol, and therefore requiring SQLite’s dependencies.

Why is Heroku skipping precompile step in Rails 3.1 app?

I'm messing around with a rails 3.1 app and deploying to Heroku Cedar.
When pushing an app, Heroku skips over the precompile step without throwing an error:
Your bundle is complete! It was installed into ./vendor/bundle
Cleaning up the bundler cache.
-----> Writing config/database.yml to read from DATABASE_URL
-----> Rails plugin injection
Injecting rails_log_stdout
Injecting rails3_serve_static_assets
-----> Discovering process types
Procfile declares types -> (none)
Default types for Ruby/Rails -> console, rake, web, worker
-----> Compiled slug size is 16.2MB
-----> Launching... done, v35
The last time I pushed to Heroku (maybe a month ago) it had no problem precompiling assets.
gem 'rails', '3.1.1.rc2', :git => 'git://github.com/rails/rails.git', :branch => '3-1-stable'
UPDATE:
I was able to get Heroku to precompile by removing the following from application.rb:
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require *Rails.groups(:assets => %w(development test))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
and replacing with:
# If you have a Gemfile, require the gems listed there, including any gems
# you've limited to :test, :development, or :production.
Bundler.require *Rails.groups(:assets) if defined?(Bundler)
I know this may sound conceiting, but did you make sure you create the Heroku app with -stack cedar?
You could also check to see that sprockets is enabled as I did here when I was having the same problem.

Resources