Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to precompile assets with Chef?

OpsWorks isn't precompiling assets on deploy. I found this recipe in this thread but I think it's not complete though, or missing something because I get an error about release_path not being found.

precompile.rb:

Chef::Log.info("Running deploy/before_migrate.rb...")

Chef::Log.info("Symlinking #{release_path}/public/assets to #{new_resource.deploy_to}/shared/assets")

link "#{release_path}/public/assets" do
  to "#{new_resource.deploy_to}/shared/assets"
end

rails_env = new_resource.environment["RAILS_ENV"]
Chef::Log.info("Precompiling assets for RAILS_ENV=#{rails_env}...")

execute "rake assets:precompile" do
  cwd release_path
  command "bundle exec rake assets:precompile"
  environment "RAILS_ENV" => rails_env
end

logs:

undefined local variable or method `release_path' for ....

Any ideas? I do not know Chef at all and am trying to figure this out on the fly.

like image 739
manafire Avatar asked Jun 11 '13 20:06

manafire


People also ask

How do you Precompile Rails assets?

To compile your assets locally, run the assets:precompile task locally on your app. Make sure to use the production environment so that the production version of your assets are generated. A public/assets directory will be created. Inside this directory you'll find a manifest.

What is assets Precompile?

rails assets:precompile is the task that does the compilation (concatenation, minification, and preprocessing). When the task is run, Rails first looks at the files in the config.assets.precompile array. By default, this array includes application.js and application.css .


2 Answers

Before OpsWorks supports the Asset Pipeline out of the box, you could do this. Create a file deploy/before_symlink.rb with the following content in your rails application.

run "cd #{release_path} && RAILS_ENV=production bundle exec rake assets:precompile"

If you deploy your Rails application to a different environment, change the RAILS_ENV.

If you use a NGINX/Unicorn stack, you have to modify the /assets resource. Just copy the following content in a file named unicorn/templates/default/nginx_unicorn_web_app.erb in your cookbooks.

upstream unicorn_<%= @application[:domains].first %> {
 server unix:<%= @application[:deploy_to]%>/shared/sockets/unicorn.sock fail_timeout=0;
}

server {
  listen 80;
  server_name <%= @application[:domains].join(" ") %> <%= node[:hostname] %>;
  access_log <%= node[:nginx][:log_dir] %>/<%= @application[:domains].first %>.access.log;

  keepalive_timeout 5;

  root <%= @application[:absolute_document_root] %>;

  <% if @application[:nginx] && @application[:nginx][:client_max_body_size] %>
    client_max_body_size <%= @application[:nginx][:client_max_body_size] %>;
  <% end %>

  location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    # If you don't find the filename in the static files
    # Then request it from the unicorn server
    if (!-f $request_filename) {
      proxy_pass http://unicorn_<%= @application[:domains].first %>;
      break;
    }
  }

  location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
  }

  location ~ ^/assets/ {
    expires 1y;
    add_header Cache-Control public;

    add_header ETag "";
    break;
  }

  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root <%= @application[:absolute_document_root] %>;
  }
}

<% if @application[:ssl_support] %>
server {
  listen   443;
  server_name <%= @application[:domains].join(" ") %> <%= node[:hostname] %>;
  access_log <%= node[:nginx][:log_dir] %>/<%= @application[:domains].first %>-ssl.access.log;

  ssl on;
  ssl_certificate /etc/nginx/ssl/<%= @application[:domains].first %>.crt;
  ssl_certificate_key /etc/nginx/ssl/<%= @application[:domains].first %>.key;
  <% if @application[:ssl_certificate_ca] -%>
  ssl_client_certificate /etc/nginx/ssl/<%= @application[:domains].first %>.ca;
  <% end -%>

  keepalive_timeout 5;

  root <%= @application[:absolute_document_root] %>;

  <% if @application[:nginx] && @application[:nginx][:client_max_body_size] %>
    client_max_body_size <%= @application[:nginx][:client_max_body_size] %>;
  <% end %>

  location / {
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    # If you don't find the filename in the static files
    # Then request it from the unicorn server
    if (!-f $request_filename) {
      proxy_pass http://unicorn_<%= @application[:domains].first %>;
      break;
    }
  }

  location ~ ^/assets/ {
    expires 1y;
    add_header Cache-Control public;

    add_header ETag "";
    break;
  }

  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root <%= @application[:absolute_document_root] %>;
  }
}
<% end %>

If you use a Apache2/Passenger stack, you have to modify the /assets resource. Just copy the following content in a file named passenger_apache2/templates/default/web_app.conf.erb in your cookbooks.

<VirtualHost *:80>
  ServerName <%= @params[:server_name] %>
  <% if @params[:server_aliases] && !@params[:server_aliases].empty? -%>
  ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %>
  <% end -%>

  <% if @params[:mounted_at] -%>
  DocumentRoot /var/www
  <%= @params[:deploy][:passenger_handler] -%>BaseURI <%= @params[:mounted_at] %>
  <% else -%>
  DocumentRoot <%= @params[:docroot] %>
  <%= @params[:deploy][:passenger_handler] -%>BaseURI /
  <% end -%>
  <%= @params[:deploy][:passenger_handler] -%>Env <%= @params[:rails_env] %>

  <Directory <%= @params[:docroot] %>>
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>

  <Directory ~ "\.svn">
    Order allow,deny
    Deny from all
  </Directory>

  <Directory ~ "\.git">
    Order allow,deny
    Deny from all
  </Directory>

  <LocationMatch "^/assets/.*$">
    Header unset ETag
    FileETag None
    # RFC says only cache for 1 year
    ExpiresActive On
    ExpiresDefault "access plus 1 year"
  </LocationMatch>

  LogLevel info
  ErrorLog <%= node[:apache][:log_dir] %>/<%= @params[:name] %>-error.log
  CustomLog <%= node[:apache][:log_dir] %>/<%= @params[:name] %>-access.log combined
  CustomLog <%= node[:apache][:log_dir] %>/<%= @params[:name] %>-ganglia.log ganglia

  FileETag none

  RewriteEngine On
  Include <%= @params[:rewrite_config] %>*
  RewriteLog <%= node[:apache][:log_dir] %>/<%= @application_name %>-rewrite.log
  RewriteLogLevel 0

  # Canonical host
  #RewriteCond %{HTTP_HOST}   !^<%= @params[:server_name] %> [NC]
  #RewriteCond %{HTTP_HOST}   !^$
  #RewriteRule ^/(.*)$        http://<%= @params[:server_name] %>/$1 [L,R=301]

  RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|jpeg|png)$
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /system/maintenance.html [L]

  Include <%= @params[:local_config] %>*
</VirtualHost>

<% if node[:deploy][@application_name][:ssl_support] -%>
<VirtualHost *:443>
  ServerName <%= @params[:server_name] %>
  <% if @params[:server_aliases] && !@params[:server_aliases].empty? -%>
  ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %>
  <% end -%>

  SSLEngine on
  SSLProxyEngine on
  SSLCertificateFile <%= node[:apache][:dir] %>/ssl/<%= @params[:server_name] %>.crt
  SSLCertificateKeyFile <%= node[:apache][:dir] %>/ssl/<%= @params[:server_name] %>.key
  <% if @params[:ssl_certificate_ca] -%>
  SSLCACertificateFile <%= node[:apache][:dir] %>/ssl/<%= @params[:server_name] %>.ca
  <% end -%>
  SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0

  <% if @params[:mounted_at] -%>
  DocumentRoot /var/www
  <%= @params[:deploy][:passenger_handler] -%>BaseURI <%= @params[:mounted_at] %>
  <% else -%>
  DocumentRoot <%= @params[:docroot] %>
  <%= @params[:deploy][:passenger_handler] -%>BaseURI /
  <% end -%>
  <%= @params[:deploy][:passenger_handler] -%>Env <%= @params[:rails_env] %>

  <Directory <%= @params[:docroot] %>>
    Options FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
  </Directory>

  <Directory ~ "\.svn">
    Order allow,deny
    Deny from all
  </Directory>

  <Directory ~ "\.git">
    Order allow,deny
    Deny from all
  </Directory>

  <LocationMatch "^/assets/.*$">
    Header unset ETag
    FileETag None
    # RFC says only cache for 1 year
    ExpiresActive On
    ExpiresDefault "access plus 1 year"
  </LocationMatch>

  LogLevel info
  ErrorLog <%= node[:apache][:log_dir] %>/<%= @params[:name] %>-ssl-error.log
  CustomLog <%= node[:apache][:log_dir] %>/<%= @params[:name] %>-ssl-access.log combined
  CustomLog <%= node[:apache][:log_dir] %>/<%= @params[:name] %>-ssl-ganglia.log ganglia

  FileETag none

  RewriteEngine On
  Include <%= @params[:rewrite_config] %>-ssl*
  RewriteLog <%= node[:apache][:log_dir] %>/<%= @application_name %>-ssl-rewrite.log
  RewriteLogLevel 0

  # Canonical host
  #RewriteCond %{HTTP_HOST}   !^<%= @params[:server_name] %> [NC]
  #RewriteCond %{HTTP_HOST}   !^$
  #RewriteRule ^/(.*)$        http://<%= @params[:server_name] %>/$1 [L,R=301]

  RewriteCond %{REQUEST_URI} !\.(css|gif|jpg|jpeg|png)$
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /system/maintenance.html [L]

  Include <%= @params[:local_config] %>-ssl*
</VirtualHost>
<% end -%>

If you have questions feel free to ask.

Best Daniel

EDIT:

Or you just copy over this cookbooks https://github.com/neonlex/massive-octo-computing-machine I developed quickly. But OpsWorks should support this by default in the future.

like image 106
Daniel Spangenberg Avatar answered Sep 28 '22 17:09

Daniel Spangenberg


Note that if you're passing environment variables to your Rails app using the new OpsWorks feature, you'll need to include these variables in your rake invocation (as they don't get permanently sourced into the deploy user's environment).

I do the following (based on this article and this recipe) in deploy/before_migrate.rb:

Chef::Log.info("Precompiling assets for RAILS_ENV=" \
               "#{new_resource.environment['RAILS_ENV']}...")

execute 'rake assets:precompile' do
  cwd release_path
  command 'bundle exec rake assets:precompile'
  environment new_resource.environment
end
like image 45
Ross Avatar answered Sep 28 '22 16:09

Ross