Rails 3.1 - how can I tell if assets are precompiling on production? - deployment

Trying to get the hang of deploying a rails 3.1 App ...
Based on what I've read, I've put the following code in my deploy.rb:
before "deploy:symlink", "assets:precompile"
namespace :assets do
desc "Compile assets"
task :precompile, :roles => :app do
run "cd #{release_path} && rake RAILS_ENV=#{rails_env} assets:precompile"
end
end
But to tell you the truth, I can't notice any difference with or without it. Is there something I'm missing here?
EDIT* found the answer:
http://spreecommerce.com/blog
To pre-compile assets for production you would normally execute the following rake task (on the production server).
$ bundle exec rake assets:precompile
This would write all the assets to the public/assets directory while including an MD5 fingerprint in the filename for added caching benefits.
NOTE: In production all references to assets from views using image_tag, asset_path, javascript_include_tag, etc. will automatically include this fingerprint in the file name so the correct version will be served.

There is configuration to do, but it should be correctly set by default. Get in your config/application.rb and see if you find this:
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
...
config.assets.enabled = true
You should also have those in your production.rb file:
# Compress JavaScripts and CSS
config.assets.compress = true
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
This should be set that way. Is it?

Related

capistrano's Capfile conditional require based on stage

I want to require capistrano/postgresql only if stage is not production.
However, this Capfile always require capistrano/postgresql because fetch(:stage) is empty.
( puts fetch(:stage) || "no stage" in Capfile prints "no stage")
require 'capistrano/bundler'
require 'capistrano/npm'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/puma'
require 'capistrano/puma/nginx'
require 'capistrano/postgresql' unless fetch(:stage) == "production"
require 'capistrano/secrets_yml'
Should I put require 'capistrano/postgresql' in config/deploy/staging.rb etc.. (I don't know whether it works or not)?
Or is there any other concise way?
EDIT
If I put require 'capistrano/postgresql' in config/deploy/staging.rb, the following error appears.
WARNING: load:defaults has already been invoked and can no longer be modified.
Check that you haven't loaded a Capistrano plugin in deploy.rb by mistake.
Plugins must be loaded in the Capfile to initialize properly.
(Backtrace restricted to imported tasks)
cap aborted!
can't modify frozen #<Class:#<Rake::Task:0x007fd8bcd22868>>
In Capefile add
task :use_postgresql do
require 'capistrano/postgresql'
end
task 'staging' => [:use_postgresql]
In that way capistrano will use posgresql only on staging env

capistrano upload! thinks ~ referenced local directory is on remote server

So every example I've looked up indicates this is how one is supposed to do it but I think I may have found a bug unless there's another way to do this.
I'm using upload! to upload assets to a remote list of servers. The task looks like this:
desc "Upload grunt compiled css/js."
task :upload_assets do
on roles(:all) do
%w{/htdocs/css /htdocs/js}.each do |asset|
upload! "#{fetch(:local_path) + asset}", "#{release_path.to_s + '/' + asset}", recursive: true
end
end
end
If local_path is defined as an absolute path such as:
set :local_path:, '/home/dcmbrown/projects/ABC'
This works fine. However if I do the following:
set :local_path:, '~/projects/ABC'
I end up getting the error:
The deploy has failed with an error: Exception while executing on ec2-54-23-88-125.us-west-2.compute.amazon.com: No such file or directory - ~/projects/ABC/htdocs/css
It's not a ' vs " issue as I've tried both (and I didn't think capistrano paid attention to that anyway).
Is this a bug? Is there a work around? Am I just doing it wrong?
I ended up discovering the best way to do this is to actually use path expansion! (headsmack)
irb> File.expand_path('~dcmbrown/projects/ABC')
=> "/home/dcmbrown/projects/ABC"
Of course what I'd like is to do automatic path expansion but you can't have everything. I think I was mostly dumbstruck that it didn't automatically; so much so I spent a couple of hours trying to figure out why it didn't work and ended up wasting time asking here. :(
I don't think the error is coming from the remote server, it just looks like it since it's running that upload command in the context of a deploy.
I just created a single cap task to just do an upload using the "~" character and it also fails with
cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as deploy#XXX: No such file or directory # rb_file_s_stat - ~/Projects/testapp/public/404.html
It appears to be a Ruby issue not Capistrano as this also fails in a Ruby console
~/Projects/testapp $ irb
2.2.2 :003 > File.stat('~/Projects/testapp/public/404.html')
Errno::ENOENT: No such file or directory # rb_file_s_stat - ~/Projects/testapp/public/404.html
from (irb):3:in `stat'
from (irb):3
from /Users/supairish/.rvm/rubies/ruby-2.2.2/bin/irb:11:in `<main>'

capistrano v2 not failing / rolling back when custom task fails

i have to compile a custom c coded binary used by our rails app.
this setup is held in a custom rake file (ourapp.rake, below)
running cap v2 i noticed the make was failing but the deploy didn't "fail".
i since just made the task
system "cd #{thedir} && exit 1" # simulate failing of custom task
but the deploy:cold doesn't fail, the debug output (below) clearly shows make failing
am i missing something? i've tried
searching for error codes/failing scenario of capistrano - nothing (lots of mentions of trying to run custom scripts on failing)
system v run v invoke
help appreciated, code below
# ourapp.rake
namespace :ourapp do
desc "Compile and Install Performant Parser"
task :compile_performant_parser do
thedir=File.join(Rails.root, 'parser')
system "cd #{thedir} && make clean && make && make install"
end # compile
desc "Compile and Install Compareplans process"
task :compile_binary do
thedir=File.join(Rails.root, 'compareplans_process/src')
#system "cd #{thedir} && make clean && make && make install"
system "exit 1"
end # compile
task :install => [:compile_performant_parser, :compile_binary ] do
puts "Preparing Ourapp for run"
end
end
additions to deploy.rb
namespace :deploy do
desc "setup ourapp dependencies, dir, binaries and (later data)"
task :setup_ourapp do
run "cd #{current_release} && /usr/bin/env bundle exec rake our app:install RAILS_ENV=#{rails_env}"
end
after 'deploy:update_code', 'deploy:setup_ourapp'
end
so i figured out that capistrano does not exit, so you need to test the error code
Capistrano run local command exit on failure
and to rollback you need to use a transaction type
How do I use transactions within custom capistrano tasks?

Creating and calling custom deployment task using run_locally in Capistrano version 3

I have a static page that I want to compile locally using gulp. The command I would run in the local shell, from the directory that contains gulp and the gulpfile (set by compile_path in this example) would be "$> gulp build".
# config valid only for Capistrano 3.1
lock '3.1.0'
set :application, 'appname'
set :repo_url, 'git#bitbucket.org/appname.git'
set :compile_path, '/Users/nico/DevOps/repo/appname'
# Default branch is :master
set :branch, 'cap3'
namespace :deploy do
after :started, :notify do
desc 'Run gulp to compile the static site'
task :gulp_build do
run_locally do
execute "#{fetch(:compile_path)}/gulp", " build"
end
end
end
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
# Your restart mechanism here, for example:
# execute :touch, release_path.join('tmp/restart.txt')
end
end
after :publishing, :restart
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
# Here we can do anything such as:
# within release_path do
# execute :rake, 'cache:clear'
# end
end
end
end
Basically, what I'm trying to achieve is a local precompile so that my deployment consists of simply sending the locally compiled files to a deployment location. when I execute "bundle exec cap staging deploy:gulp_build" I get:
cap aborted!
Don't know how to build task 'deploy:gulp_build'
/Users/nico/.rvm/gems/ruby-1.9.3-p545/gems/capistrano-3.1.0/lib/capistrano/application.rb:15:in run'
/Users/nico/.rvm/gems/ruby-1.9.3-p545/gems/capistrano-3.1.0/bin/cap:3:in'
/Users/nico/.rvm/gems/ruby-1.9.3-p545/bin/cap:23:in load'
/Users/nico/.rvm/gems/ruby-1.9.3-p545/bin/cap:23:in'
/Users/nico/.rvm/gems/ruby-1.9.3-p545/bin/ruby_executable_hooks:15:in eval'
/Users/nico/.rvm/gems/ruby-1.9.3-p545/bin/ruby_executable_hooks:15:in'
(See full trace by running task with --trace)
I realize that there are probably much better ways to deploy this, but it's a companion static site to a rails app which is being deployed successfully via capistrano, and I'd like to just use the same deployment method for both.
This was handled pretty well by creating a new task in the deploy namespace. in my code below are placeholders for real values that I didn't want to post on SO.
lib/capistrano/tasks/gulp_build_local.cap:
#assumes the gulpfile is in root of your cap install
namespace :deploy do
desc 'Run gulp to compile the static site'
task :gulp_build do
#run_locally doesn't play nice with the 'on' directive (it's 'on' localhost)
run_locally do
execute "gulp build"
end
end
end
deploy.rb:
# config valid only for Capistrano 3.1
lock '3.1.0'
set :application, '<appname>'
set :repo_url, 'git#bitbucket.org/<appname>.git'
namespace :deploy do
#custom tasks to build via gulp
before :deploy, 'gulp_build_local'
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
#nothing here, because there's no app server for this static site.
end
end
after :publishing, :restart
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
#nothing here
end
end
end
of course, once I figured this out I immediately deprecated it in favor of new tasks to install gulp in the release dir on the target, compiling there and linking the site root to the pub folder generated by the gulp process. Hopefully this learning experience will be useful for someone working though the use of run_locally, though.

Padrino + sinatra-assetpack not working

I'm trying to combine Padrino with Sinatra-Assetpack, without success.
This is my Gemfile:
source :rubygems
gem 'rake'
gem 'sinatra-flash', :require => 'sinatra/flash'
# Component requirements
gem 'haml'
# Assets requirements
gem 'sinatra-assetpack', :require => 'sinatra/assetpack'
# Test requirements
# Padrino Stable Gem
gem 'padrino', '0.10.6'
in my app/app.rb file I set:
require 'sinatra/assetpack'
class Coffee < Padrino::Application
register Padrino::Rendering
register Padrino::Mailer
register Padrino::Helpers
register Sinatra::AssetPack
assets {
serve '/js', from: '/app/assets/javascripts'
serve '/css', from: '/app/assets/stylesheets'
css :main, ['/css/main.css']
js :application, ['/js/application.js']
}
enable :sessions
end
my javascript files are in /app/assets/javascripts and css files in /app/assets/stylesheets, but Padrino respond with a 404 for both /css/main.css and /js/application.js
Any ideas?
Thanks
Figured out the issue, in my application anyway, but from the looks of your app.rb code it's probably the same for you;
Assetpack serves files from the directories you specify in your serve calls, relative to your application's root. In padrino, the application root is yourapplication/app, so if you tell assetpack to serve css from /app/assets/stylesheets for instance, its really looking for the files in yourapplication/app/app/assets/stylesheets.
The second part of the problem was that in the AssetPack docs, it shows the code
set :root, File.dirname(__FILE__)
before the register Sinatra::AssetPack line, which I assume is setting the application's root directory properly so that AssetPack will look in the root application directory instead of app. However, even If I modified that call to set to go up one directory from the app.rb file (since it sits in the app dir in Padrino), it didn't seem to have any effect on AssetPack.
In short, modifying the from: paths in the `serve' calls to be relative to your app directory should fix the problem. In your case, they should be:
serve '/js', from: '/assets/javascripts'
serve '/css', from: '/assets/stylesheets'