Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assets won't precompile when deploying with capistrano to production on amazon EC2

I worked on being able to deploy to production using capistrano. I face several issues and while fixing most of them we still have a last one.

Our precompile assets options are not properly compiling them on production and because of that, we are unable to use the last developed features as they rely heavily on JS.

Without trying to influence on how anyone would analyze this problem, this is some of what I did trying to make it work:

  1. Precompiled assets locally, pushed to github repo, cap deployed from local machines to ec2. cap deploy is local, the code being pushed to ec2 is the one on github.
  2. Tried using capistrano tasks as suggested. Using load 'deploy'assets' in the Capfile and letting the cap deploy:setup task do its thing.
  3. Used the option cap deploy:assets:clean and then cap deploy:assets:precompile
  4. Tried removing assets from public and then use a pipeline_precompile task in deploy.rb
  5. Expired assets, forcing rails to precompile everything changing assets.versions in application.rb
  6. Tried different combinations on config.assets in environments/production.rb
  7. Finally, tried deleting public/assets in production and precompiling up there using RAILS_ENV=production bundle exec rake assets:precompile

The app is just not using the new JS files. If you check the code either on the repo or in the server itself, I introduced a simple comment to the name.js.coffee ("# Shows and hides menus depending on the data on DB" on line xxx) and this is not in the compiled assets.js in production. This is a quick test to be sure the recent assets are being used.

The whole problem here is the js and css files, not so much rails. Which is why it is so difficult to test or find.. Thus one of the reasons for the popularity of js frameworks lately. In case of problems, you don't have to kill yourself looking for where the problem is.. If the prob is in ruby or rails, usually doesn't take that long to find out. Once you get to js, css and cross browser compatibility, well, this IS the problem at hand.

Here's my deploy.rb file. Running rails 3.2.12 ruby-1.9.3-p327:

# $:.unshift(File.expand_path('./lib', ENV['rvm_path']))

# Load rvm's capistrono plugins
require 'rvm/capistrano'

require 'bundler/capistrano'

set :rvm_type, :user

set :user, 'username'
set :domain, 'ip_address'
set :application, "app_pro"
set :keep_releases, 2 # It keeps on two old releases.

# git repo details
set :scm, :git # You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
set :repository,  "[email protected]:user/app.git"
set :scm_username, 'user'
set :git_enable_submodules, 1
set :git_shallow_clone, 1
set :branch, 'master'

# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`


role :web, domain                          # Your HTTP server, Apache/etc
role :app, domain                          # This may be the same as your `Web` server
role :db,  domain, :primary => true# 'ec2-23-23-156-118.compute-1.amazonaws.com' This is where Rails migrations will run
# role :db,  "your slave db-server here"

# deply options
default_run_options[:pty] = true
set :ssh_options, {:forward_agent => true}
set :ssh_options, {:auth_methods => "publickey"}
set :ssh_options, {:keys => ["~/Downloads/key.pem"]}
set :deploy_to, "/home/user/appdir"
set :deploy_via, :remote_cache
set :use_sudo, false

# if you want to clean up old releases on each deploy uncomment this:
after "deploy:restart", "deploy:cleanup"

# if you're still using the script/reaper helper you will need
# these http://github.com/rails/irs_process_scripts

# If you are using Passenger mod_rails uncomment this:
namespace :deploy do
  task :start do
    # run COMMAND="/etc/init.d/nginx restart" invoke SUDO=1
    run "sudo /etc/init.d/nginx restart"
    # exit
  end
  after "deploy:start", "deploy:cleanup"

  task :stop do ; end
  task :restart, :roles => :app, :except => { :no_release => true } do
    run "touch #{File.join(current_path,'tmp','restart.txt')}"
  end

  task :setup_config, roles: :app do
    run "mkdir -p #{shared_path}/config"
    put File.read("config/database.example.yml"), "#{shared_path}/config/database.yml"
    puts 'now edit the config file database in #{shared_path}'
  end
  after 'deploy:setup', 'deploy:setup_config'

  desc "Symlink shared resources on each release - not used"
  task :symlink_config, :roles => :app do
    run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
  end

  after 'deploy:finalize_update', 'deploy:symlink_config'

  desc "It helps to seed database with values"
  task :seed do
    run "cd #{current_path}; bundle exec rake db:seed RAILS_ENV=#{rails_env}"
  end
  task :create_schema do
    run "cd #{current_path}; bundle exec rake db:create RAILS_ENV=#{rails_env} --trace"
  end
end

On-working new/alternative (deploy_new2.rb) file:

# On-working new/alternative deploy.rb file:

require 'rvm/capistrano'
require 'bundler/capistrano'

set :rvm_type, :user

set :application, "ip_address"
set :domain, 'ip_address'

# Roles
role :web, domain
role :app, domain
role :db,  domain, :primary => true

#deployment details
set :deploy_via, :remote_cache
set :user, "username"
set :copy_compression, :bz2
set :git_shallow_clone, 1
set :scm_verbose, true
set :use_sudo, false
set :deploy_to, "/home/user/dir"

default_run_options[:pty] = true
set :ssh_options, {:forward_agent => true}
set :ssh_options, {:auth_methods => "publickey"}
set :ssh_options, {:keys => ["~/Downloads/key.pem"]}

#repo details
set :scm, :git
set :repository,  "[email protected]:user/app.git"
set :scm_username, 'user'
set :keep_releases, 2
set :branch, "master"


namespace :deploy do
  # task :start, :roles => :app, :except => { :no_release => true } do
  #   # not need to restart nginx every time
  #   # run "service nginx start"
  #   run "cd #{release_path} && touch tmp/restart.txt"
  # end

  # after "deploy:start", "deploy:cleanup"
  # after 'deploy:cleanup', 'deploy:symlink_config'

  # You do not need reload nginx every time, eventhought if you use passenger or unicorn
  # task :stop, :roles => :app, :except => { :no_release => true } do
  #   run "service nginx stop"
  # end

  # task :graceful_stop, :roles => :app, :except => { :no_release => true } do
  #   run "service nginx stop"
  # end

  # task :reload, :roles => :app, :except => { :no_release => true } do
  #   run "cd #{release_path} && touch tmp/restart.txt"
  #   run "service nginx restart"
  # end

  task :restart, :roles => :app, :except => { :no_release => true } do
    run "cd #{release_path} && touch tmp/restart.txt"
  end

  # If you enable assets/deploy in Capfile, you do not need this
  # task :pipeline_precompile do
  #   # run "cd #{release_path}; RAILS_ENV=#{rails_env} bundle exec rake assets:precompile"
  #   # precompile assets before deploy and upload them to server 
  #   # run_locally("RAILS_ENV=#{rails_env} rake assets:clean && RAILS_ENV=#{rails_env} rake assets:precompile")
  #   # top.upload "public/assets", "#{release_path}/public/assets", :via =>:scp, :recursive => true
  # end
end

# you do not need to this, because you already add require 'bundler/capistrano'
# before "deploy:assets:precompile", "bundle:install"

And ./Capfile:

load 'deploy'
# Uncomment if you are using Rails' asset pipeline
load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks

Thank you in advance for any help! Let me know if you need more info.

like image 520
TKVR Avatar asked Mar 23 '13 00:03

TKVR


3 Answers

You don't need your own :precompile_assets task. You are using Capistrano's by including load 'deploy/assets' in your Capfile.

Removing the :precompile_assets task from your deploy.rb may resolve the issue. If you look at the source code for Capistrano, you'll see it implements :precompile_assets quite differently: https://github.com/capistrano/capistrano/blob/legacy-v2/lib/capistrano/recipes/deploy/assets.rb

like image 105
Chris Aitchison Avatar answered Nov 06 '22 18:11

Chris Aitchison


You can try this code

# On-working new/alternative deploy.rb file:

require 'rvm/capistrano'
require 'bundler/capistrano'

set :rvm_type, :user

set :application, "ip_address"
set :domain, 'ip_address'

# Roles
role :web, domain
role :app, domain
role :db,  domain, :primary => true

#deployment details
set :deploy_via, :remote_cache
set :user, "username"
set :copy_compression, :bz2
set :git_shallow_clone, 1
set :scm_verbose, true
set :use_sudo, false
set :deploy_to, "/home/user/dir"

default_run_options[:pty] = true
set :ssh_options, {:forward_agent => true}
set :ssh_options, {:auth_methods => "publickey"}
set :ssh_options, {:keys => ["~/Downloads/key.pem"]}

#repo details
set :scm, :git
set :repository,  "[email protected]:user/app.git"
set :scm_username, 'user'
set :keep_releases, 2
set :branch, "master"


namespace :deploy do
  # task :start, :roles => :app, :except => { :no_release => true } do
  #   # not need to restart nginx every time
  #   # run "service nginx start"
  #   run "cd #{release_path} && touch tmp/restart.txt"
  # end

  # after "deploy:start", "deploy:cleanup"
  # after 'deploy:cleanup', 'deploy:symlink_config'

  # You do not need reload nginx every time, eventhought if you use passenger or unicorn
  # task :stop, :roles => :app, :except => { :no_release => true } do
  #   run "service nginx stop"
  # end

  # task :graceful_stop, :roles => :app, :except => { :no_release => true } do
  #   run "service nginx stop"
  # end

  # task :reload, :roles => :app, :except => { :no_release => true } do
  #   run "cd #{release_path} && touch tmp/restart.txt"
  #   run "service nginx restart"
  # end

  task :restart, :roles => :app, :except => { :no_release => true } do
    run "cd #{release_path} && touch tmp/restart.txt"
  end

  # If you enable assets/deploy in Capfile, you do not need this
  # task :pipeline_precompile do
  #   # run "cd #{release_path}; RAILS_ENV=#{rails_env} bundle exec rake assets:precompile"
  #   # precompile assets before deploy and upload them to server 
  #   # run_locally("RAILS_ENV=#{rails_env} rake assets:clean && RAILS_ENV=#{rails_env} rake assets:precompile")
  #   # top.upload "public/assets", "#{release_path}/public/assets", :via =>:scp, :recursive => true
  # end
end

# you do not need to this, because you already add require 'bundler/capistrano'
# before "deploy:assets:precompile", "bundle:install"
like image 1
Hendra Gunawan Avatar answered Nov 06 '22 20:11

Hendra Gunawan


Solution: Here's the working deploy file-

require 'rvm/capistrano'
require 'bundler/capistrano'

set :rvm_type, :user

set :application, "ip_address"
set :domain, 'ip_address'

# Roles
role :web, domain
role :app, domain
role :db,  domain, :primary => true

#deployment details
set :deploy_via, :remote_cache
set :user, "user"
set :copy_compression, :bz2
set :git_shallow_clone, 1
set :scm_verbose, true
set :use_sudo, false
set :deploy_to, "/home/user/app_dir"

default_run_options[:pty] = true
set :ssh_options, {:forward_agent => true}
set :ssh_options, {:auth_methods => "publickey"}
set :ssh_options, {:keys => ["~/sites/app/config/key.pem"]}

#repo details
set :scm, :git
set :repository,  "[email protected]:github_id/app.git"
set :scm_username, 'github_id'
set :keep_releases, 2
set :branch, "master"

after 'deploy:update_code', 'deploy:symlink_db'

namespace :deploy do
  # task :start, :roles => :app, :except => { :no_release => true } do
  #   # not need to restart nginx every time
  #   # run "service nginx start"
  #   run "cd #{release_path} && touch tmp/restart.txt"
  # end

  # after "deploy:start", "deploy:cleanup"
  # after 'deploy:cleanup', 'deploy:symlink_config'

  # You do not need reload nginx every time, eventhought if you use passenger or unicorn
  # task :stop, :roles => :app, :except => { :no_release => true } do
  #   run "service nginx stop"
  # end

  # task :graceful_stop, :roles => :app, :except => { :no_release => true } do
  #   run "service nginx stop"
  # end

  # task :reload, :roles => :app, :except => { :no_release => true } do
  #   run "cd #{release_path} && touch tmp/restart.txt"
  #   run "service nginx restart"
  # end

  task :restart, :roles => :app, :except => { :no_release => true } do
    run "cd #{release_path} && touch tmp/restart.txt"
  end

  desc "Symlinks the database.yml"
  task :symlink_db, :roles => :app do
    run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
  end

  # If you enable assets/deploy in Capfile, you do not need this
  # task :pipeline_precompile do
  #   # run "cd #{release_path}; RAILS_ENV=#{rails_env} bundle exec rake assets:precompile"
  #   # precompile assets before deploy and upload them to server 
  #   # run_locally("RAILS_ENV=#{rails_env} rake assets:clean && RAILS_ENV=#{rails_env} rake assets:precompile")
  #   # top.upload "public/assets", "#{release_path}/public/assets", :via =>:scp, :recursive => true
  # end
end

# you do not need to this, because you already add require 'bundler/capistrano'
# before "deploy:assets:precompile", "bundle:install"
like image 1
TKVR Avatar answered Nov 06 '22 19:11

TKVR