Loading initializers during assets precompile - ruby-on-rails

I am trying to precompile the assets while deploying to production environment. I am also trying to automate it for first time installation on a server using capistrano. It looks like none of the initializer's are getting loaded during the assets precompile process.
I am facing these two problems
For the first time installation I am generating a initializer file(initializers/freshinstall.rb) on the fly with the below content
config.assets.initialize_on_precompile = false
so that precompile doesn't check the database which doesn't exist yet
I also have some vendor files, and their locations are set in the asset pipeline, and are placed in separate initializer file initializers/vendor.rb
MyApp::Application.config.assets.paths << "#Rails.root}/vendor/assets/images/xxxx" << "# {Rails.root}/vendor/assets/images/xxxx/helpers"
MyApp::Application.config.assets.paths << "#{Rails.root}/vendor/assets/stylesheets/xxxx"
MyApp::Application.config.assets.paths << "#{Rails.root}/vendor/assets/stylesheets/yyyy" << "#{Rails.root}/vendor/assets/images/yyyy"
When capistrano runs the assets precompile task, its not able to find the vendor paths or stopping it from looking into the database. This brings me to a conclusion that the initializer's are not getting loaded. After going through some stackoverflow questions. I even added a railtie to config/application.rb
module AssetsInitializers
class Railtie < Rails::Railtie
initializer "assets_initializers.initialize_rails",
:group => :assets do |app|
require "#{Rails.root}/config/initializers/freshinstall.rb"
require "#{Rails.root}/config/initializers/vendor.rb"
end
end
end
But I still don't see any initializers getting loaded. Can I get some info on the internals of the boot process of an rail application, and also why the initializers are not getting loaded during the assets precompile process.
Some documentations would be really helpful to understand this. The Rails documentation is very minimal with respect to railtie and the initializer method.
http://guides.rubyonrails.org/configuring.html
Thank you in advance

Finally was able to figure out how to do it. This works for my single server capistrano deployment. Below is the capistrano task for my new_deploy on to a fresh server.
set :fresh_install, false
task :new_deploy do
set :fresh_install,true
deploy.setup
#The assets:precompile process is part of the deploy.update. Before the precompile process, we will create database.
deploy.update
deploy.migrate
run_seed
#load unicorn server
end
Dont do any configuration setting mentioned below
config.assets.initialize_on_precompile = false # no need of this in application.rb
Instead just before assets:precompile create your database
before "deploy:assets:precompile" , "yourapp:create_database"
See that you check if the fresh install flag is set, then only create the database.This method will also be called during regular deploy when ever you are updating the server with latest revision. During that scenario fresh_install flag will be false.
desc 'Create a new database'
task :create_database, :roles => :app do
if fresh_install
run "cd #{release_path}; bundle exec rake db:create RAILS_ENV=#{rails_env}"
end
end

Related

rake causes compilation of assets using production.rb in development mode

I am upgrading to rails 7.0.3.1 from rails 6.1.6.1. Whenever I run a rake task there is an exception generated. For example with this simple rake task
namespace :tests do
task temp: :environment do
puts "Environment is #{Rails.env}"
end
end
if I run rake tests:temp then I see the following
Precompiling assets for local
precompile asset_host is
rake aborted!
KeyError: key not found: "APPLICATION_HOST"
/Users/myname/myapp/config/environments/production.rb:8:in `fetch'
...
Tasks: TOP => environment
(See full trace by running task with --trace)
[master c970ac9] Add precompiled assets for local
2 files changed, 1593 insertions(+), 1840 deletions(-)
...
Environment is development
I can provide the full trace if requested. Note that after the exception, the rake test does work successfully. Also the code is making a git commit to the effect Add precompiled assets for local. The environment variable APPLICATION_HOST is not set in the development environment, because it is only needed in production.
I was not seeing this problem in rails 6. What is causing this?
It turns out that I have a method defined in a Mixin which looks like this
def precompile_assets(target: 'local)
puts "Precompiling assets for #{target}"
...
system("RAILS_ENV=production RAILS_HOST_PATH=#{asset_host} rake assets:precompile")
end
This was only meant to be used in rake tasks used for deployment. It looks like somewhere in Rails 7 there is another method with the same name, which is being overwritten. The quick solution is rename the method so it does not clash. The longer solution is refactor so as it is not a Mixin.
I guess all those articles about the dangers of Mixins were right.

How to force asset compilation - Rails 6

Using Rails 6.0.2.1 with Ruby 2.6.3 and NGINX
I have a rake task that has the job of re compiling assets when they change in the production server
#Called by delayed job UpdateAssetsJob
require 'rake'
desc "Applying Theme, will restart server and may take a while!"
task :apply_css => :environment do
Rails.logger.info("Applying CSS in #{Rails.env}")
if Rails.env == "production"
Rails.logger.info("Compiling Assets")
Rake::Task['assets:precompile'].invoke
Rake::Task['assets:precompile'].reenable
# `RAILS_ENV=production rails assets:precompile`
Rails.logger.info("Cleaning assets - busting cache")
Rake::Task['assets:clean'].invoke
Rake::Task['assets:clean'].reenable
# `RAILS_ENV="production" rake assets:clean`
Rails.logger.info("Restarting Puma server")
`bundle exec pumactl -S /home/app_path/shared/tmp/pids/puma.state -F /home/app_path/shared/puma.rb restart`
end
end
The problem with this is that assets will only ever be compiled once.
I have tried clobbering the assets before compiling using
#Clobber assets to force recompilation
Rails.logger.info("Clobber Assets")
Rake::Task['assets:clobber'].invoke
Rake::Task['assets:clobber'].reenable
But again this will only work once
The scenario is:
An administrator updates colours for the current application theme which causes a background task, delayed job, to write necessary changes to
assests/stylesheets/_colours.scss file
For these changes to take effect I compile the assets, clean the assets, ensuring visitors that have cached assets get the latest version and then restart the server
As I am using the partial syntax for the naming of _colours.scss I have no need for this functionality in the development environment as changes are automatically picked up
Suggestions for a more appropriate solution are welcome
Solved the issue by switching from using
Rake::Task['assets:precompile'].invoke
Rake::Task['assets:precompile'].reenable
to
RAILS_ENV=production rails assets:precompile
I do need to clobber the assets and unexplainably the assets:clobber task will run multiple times once I switched the precompile task
Problem solved

How to run bin/webpack with capistrano and rails

So I have a rails 6 app that doesn't load any css or javascript assets when I run cap production deploy.
So what I do is after I run cap production deploy, I ssh into my server, navigate to myapp/current/ and run bin/webpack and then everything works. So I'd like my deployment process to do this for me so that I don't have to go into my server and run this everytime.
I've looked on how to run custom capistrano "tasks," but all the tutorials show you only how to run custom rake tasks, but this isn't a rake task.
I don't run rake bin/webpack, i just run bin/webpack.
So how I would go about implementing this in my capistrano setup? I assume I have to enter some sort of capistrano command in my deploy.rb.
Any ideas?
Capistrano at its core is just ssh. It's doing something similar to what you're doing when you ssh (although slightly different because it's not typically an interactive session).
You could write a custom task to run Webpack.
To do that you need to load them first if they're not already being loaded.
Check for this line in your Capfile or add it yourself. This will load your custom tasks which come in the form of rake tasks:
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
Then, create a task in that folder. Call it something like lib/capistrano/tasks/webpack.rake
namespace :webpack do
task :build do
on roles(:app) do
within release_path do
# https://github.com/capistrano/sshkit#the-command-map
with path: "#{release_path}/bin:$PATH" do
execute :webpack
end
end
end
end
end
Now, you need to tell Capistrano when to execute it. I usually do this with before/after hooks. For more info check out Capistrano flow
after the namespace block add:
# lib/capistrano/tasks/webpack.rake
# ...
after "deploy:updated", "webpack:build"
you can test out task execution with bundle exec cap production deploy --dry-run

Local rake tasks require development gems to be in production group

I have some rake tasks that I only perform locally. However since I refer to the some gem classes in rake tasks, this seems to require that the gem be installed and loaded on the production server. Among other things this increases deploy time and memory usage on the server.
This may or may not have to do with my setting:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
I have a number of lib files and subdirectories.
I guess my options are to
move all my lib files somewhere else and add that path to autoload_paths
try to exclude the tasks dir from autoload_paths
do something fancy in the rake tasks themselves (if possible) to avoid the need to have the gems present.
configure rake tasks to live somewhere else (seems like a bad idea)
This seems like a pretty common issue and probably has a common way to solve it or avoid it. What am I missing?
Maybe not the most exciting answer but I just moved the require 'dev_gem' inside the rake task block for that task.
namespace :elasticbeanstalk do
desc 'Creates a new web & worker environment pair for testing'
task :create do
require 'aws-sdk-elasticbeanstalk'
# Do stuff with beanstalk that we wouldn't from a production env
end
end
This way the library only gets loaded when the rake task is invoked rather than when the rake task is defined.
doing something like this may work
require "prod_gem_name"
unless Rails.env.production?
require 'dev_gem_name'
desc "Task that run something with a dev gem"
# code that uses the gem on dev group
end
or another solution maybe will be to add those .rake files to the gitignore. maybe it wouldn't work on all cases but it's another option.

Ruby on Rails: Ran rake assets:precompile and now both local and heroku deployment don't include bootstrap

I was having issues deploying my project to a heroku server (Precompile fail). So I found this response, https://stackoverflow.com/a/13713753/2989437, and followed up on the advice. I added one line to my application.rb file:
application.rb
module FirstEdc
class Application < Rails::Application
config.assets.initialize_on_precompile = false # I added this line
...
end
end
I then ran the precompile command, committed the changes, and managed to deploy successfully to heroku. However, now my bootstrap/css appears to have stopped functioning both on the heroku deployment, and my local deployment.
I learned that I was supposed to add another line to my deployment.rb file:
deployment.rb
FirstEdc::Application.configure do
...
# Allows for local precompilling --added by Ian
config.assets.prefix = '/dev-assets'
end
So I added this, recompiled and redeployed, but to no avail.
Finally, I ran a rake assets:clean in an attempt to at least get my local deployment back to normal, but it did not work.
Any advice would be greatly appreciated. I'm reading more into the asset pipeline now, but I feel like this could be a cache problem or something. I'll update as I figure out what's going on.
edit. Just to clarify, I've tried removing both additions, running a rake assets:clean and rake assets:clean:all, but neither fix my local deployment.
I don't use config.assets.prefix in any of my apps and they work just fine with Heroku, so not sure what that's doing.
Try removing that line, then running rake assets:clean. Now your local server should be using the files as you change them. When you want to push, run rake assets:precompile first, then push.
If you want to make changes locally after that, run rake assets:clean again to get rid of the precompiled files on your local machine.
If Heroku detects any files in public/assets it will not attempt to precompile your assets again. This is by design.
So, you need to make a decision to either always precompile your assets with rake assets:precompile, or remove any files in public/assets before pushing to Heroku.
(The recommended way is to allow Heroku to precompile them during push)

Resources