Ruby-on-rails 在亚马逊 EC2 上使用 capistrano 部署到生产环境时,资产不会预编译
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15581820/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Assets won't precompile when deploying with capistrano to production on amazon EC2
提问by TKVR
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.
我致力于能够使用 capistrano 部署到生产环境。我面临着几个问题,在解决其中大部分问题的同时,我们还有最后一个。
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.
我们的预编译资产选项没有在生产中正确编译它们,因此,我们无法使用上次开发的功能,因为它们严重依赖于 JS。
Without trying to influence on how anyone would analyze this problem, this is some of what I did trying to make it work:
在不试图影响任何人如何分析这个问题的情况下,这是我为使其工作所做的一些努力:
- 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.
- Tried using capistrano tasks as suggested. Using load 'deploy'assets' in the Capfile and letting the cap deploy:setup task do its thing.
- Used the option cap deploy:assets:clean and then cap deploy:assets:precompile
- Tried removing assets from public and then use a pipeline_precompile task in deploy.rb
- Expired assets, forcing rails to precompile everything changing assets.versions in application.rb
- Tried different combinations on config.assets in environments/production.rb
- Finally, tried deleting public/assets in production and precompiling up there using RAILS_ENV=production bundle exec rake assets:precompile
- 在本地预编译资产,推送到 github repo,从本地机器部署到 ec2。cap deploy是本地的,推送到ec2的代码是github上的。
- 按照建议尝试使用 capistrano 任务。在 Capfile 中使用 load 'deploy'assets' 并让 cap deploy:setup 任务完成它的工作。
- 使用选项 cap deploy:assets:clean 然后 cap deploy:assets:precompile
- 尝试从 public 中删除资产,然后在 deploy.rb 中使用 pipeline_precompile 任务
- 过期资产,强制 Rails 预编译所有更改 application.rb 中的 assets.versions
- 在environments/production.rb 中的config.assets 上尝试了不同的组合
- 最后,尝试删除生产中的公共/资产并使用 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.
该应用程序只是不使用新的 JS 文件。如果您在 repo 或服务器本身中检查代码,我在 name.js.coffee 中引入了一个简单的注释(“#根据 DB 上的数据显示和隐藏菜单”在第 xxx 行),这不在在生产中编译的 assets.js。这是一个快速测试,以确保正在使用最近的资产。
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.
这里的整个问题是 js 和 css 文件,而不是 Rails。这就是为什么测试或发现如此困难的原因..这也是最近js框架流行的原因之一。万一出现问题,您不必为了寻找问题出在哪里而自杀。如果问题出在 ruby 或 rails 中,通常不会花那么长时间找出问题所在。一旦您了解 js、css 和跨浏览器兼容性,那么,这就是手头的问题。
Here's my deploy.rb file. Running rails 3.2.12 ruby-1.9.3-p327:
这是我的 deploy.rb 文件。运行导轨 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:
正在运行的新/替代 (deploy_new2.rb) 文件:
# 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:
和 ./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.
预先感谢您的任何帮助!如果您需要更多信息,请告诉我。
采纳答案by TKVR
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"
回答by Chris Aitchison
You don't need your own :precompile_assets task. You are using Capistrano's by including load 'deploy/assets' in your Capfile.
您不需要自己的 :precompile_assets 任务。您通过在 Capfile 中包含加载“部署/资产”来使用 Capistrano。
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
从您的 deploy.rb 中删除 :precompile_assets 任务可能会解决该问题。如果您查看 Capistrano 的源代码,您会看到它实现 :precompile_assets 的方式完全不同:https: //github.com/capistrano/capistrano/blob/legacy-v2/lib/capistrano/recipes/deploy/assets.rb
回答by Hendra Gunawan
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"
回答by mcr
I found that the capistrano asset compile rules got run before the bundler rules, so nothing worked, I wrote my own:
我发现 capistrano 资产编译规则在打包规则之前运行,所以没有任何效果,我自己写了:
after "bundle:install" do
run "cd #{release_path}; RAILS_ENV=production bundle exec rake assets:precompile"
end
I then found that I really wasn't interested in installing a js runtime on my production machines. I went back to just putting my assets into a deploy branch of my git tree. First time I did this, I forgot to include the manifest.yml file.
然后我发现我真的对在我的生产机器上安装 js 运行时不感兴趣。我回到只是将我的资产放入我的 git 树的部署分支。我第一次这样做时,忘记包含 manifest.yml 文件。
http://jimneath.org/2012/05/05/precompile-assets-using-a-git-hook.html
http://jimneath.org/2012/05/05/precompile-assets-using-a-git-hook.html
回答by KevEllis
I had an issue similar to this but the solution was to remove the assets group in the Gemfile, as the default task cap uses to precompile depends on the assets not being in a separate group seemingly.
我有一个与此类似的问题,但解决方案是删除 Gemfile 中的资产组,因为用于预编译的默认任务上限取决于资产似乎不在单独的组中。
回答by MarkDBlackwell
If you have uglifier in Gemfile, which runs during asset compilation, it may have been configured to remove just the sort of comment you are using as a test for whether the changed Javascript assets are being deployed.
如果您在 Gemfile 中有 uglifier,它在资产编译期间运行,它可能已配置为仅删除您用作测试是否正在部署更改的 Javascript 资产的那种注释。
Uglifier's Readme saysthis is possible, and distinguishes several kinds of comments. So it's possible you may have been misled by seeing another comment still remaining after asset compilation.
Uglifier 的自述文件说这是可能的,并区分了几种评论。因此,您可能会因为在资产编译后看到另一条评论仍然存在而被误导。
Another clue to judging this possibility is that (as you say) this problem arose after a long (tiring) process of fixing other problems. Often, this can block people from a perception like this; a long effort can 'lock them in' to an assumption.
判断这种可能性的另一个线索是(如您所说)这个问题是在解决其他问题的长期(累人)过程之后出现的。通常,这会阻止人们产生这样的看法;长期的努力可以将他们“锁定”在一个假设中。
So, try adding a variable declaration instead of a comment, in your Javascript.
因此,尝试在您的 Javascript 中添加变量声明而不是注释。

