Rails: Clarifying purpose of precompile:assets - ruby-on-rails

I'm trying to understand what exactly precompiling:assets does, because I've realized that for my last project my CSS would never update when I pushed my app to heroku unless I typed bundle exec rake assets:precompile, but this only started happening towards the end, so I believe I probably added something to the config file.
I'm currently trying to understand caching, which made me think about precompile:assets. Is precompile:assets similar to caching by pre-loading the assets to the web server so that those assets aren't loaded directly from the Rails stack? This is for performance purposes right?

Caching is a related, but separate topic.
The purpose of compiling assets includes the combining and minimizing of assets, e.g. javascript that is all on 1 line with 1 letter variables, as opposed to the originals which are used in development mode and let you debug there using the original source code.

You can find everything you need to know in the Asset Pipeline Rails Guide.

Related

confusing about autoload_paths vs eager_load_paths in rails 4

I read a post about the rails load_paths, here is the link.
But, I am still confused about the difference between the autoload_paths and eager_load_paths:
I have tested them in a newly created Rails 4 project. It seems that they run the same way, that auto-reload in the development mode but in the production mode.
Author of the linked article here. Here's an attempt to clear up the confusion, going off of #fkreusch's answer.
In Ruby you have to require every .rb file in order to have its code run. However, notice how in Rails you never specifically require any of your models, controllers, or other files in the app/ dir. Why is that? That's because in Rails app/* is in autoload_paths. This means that when you run your rails app in development (for example via rails console) — none of the models and controllers are actually required by ruby yet. Rails uses special magical feature of ruby to actually wait until the code mentions a constant, say Book, and only then it would run require 'book' which it finds in one of the autoload_paths. This gives you faster console and server startup in development, because nothing gets required when you start it, only when code actually needs it.
Now, this behavior is good for local development, but what about production? Imagine that in production your server does the same type of magical constant loading (autoloading). It's not the end of the world really, you start your server in production, and people start browsing your pages slightly slower, because some of the files will need to be autoloaded. Yes, it's slower for those few initial requests, while the server "warms up", but it's not that bad. Except, that's not the end of the story.
If you are running on ruby 1.9.x (if I recall correctly), then auto-requiring files like that is not thread safe. So if you are using a server like puma, you will run into problems. Even if you aren't using a multi-threaded server, you are still probably better off having your whole application get required "proactively", on startup. This means that in production, you want every model, every controller, etc all fully required as you start your app, and you don't mind the longer startup time. This is called eager loading. All ruby files get eagerly loaded, get it? But how can you do that, if your rails app doesn't have a single require statement? That's where eager_load_paths come in. Whatever you put in them, all the files in all the directories underneath those paths will be required at startup in production. Hope this clears it up.
It's important to note that eager_load_paths are not active in development environment, so whatever you put in them will not be eagerly required immediately in development, only in production.
It's also important to note that just putting something into autoload_paths will not make it eager-loaded in production. Unfortunately. You have to explicitly put it into eager_load_paths as well.
Another interesting quirk is that in every rails app, all directories under app/ are automatically in both autoload_paths and eager_load_paths, meaning that adding a directory there requires no further actions.
Basically, autoload_paths are paths Rails will use to try loading your classes automatically. E.g. when you call Book, if that class isn't loaded yet, it will go through the autoload_paths and look for it in those paths.
In production, it might be better to load those upfront to avoid autoload concurrent issues. For that, it provides the eager_load_paths. Paths in that list will be required upfront when your application starts.

Recompiling Sass assets in production

I'm working on a rails app where we want to allow the user to use an admin tool to create new themes. The admin tool is a separate application and communicates with our main application through a database. My problem is that I've written custom Sass extensions to load our data into our style sheets, but once that is done, I am unable to recompile the assets in our production environment.
So far I've seen two possibilities for this:
1.Increment the version of config.assets.version. So I have this code:
MyApp::Application.assets.version =
(MyApp::Application.config.assets.version.to_i + .1)
From what I've read incrementing this should cause the assets to recompile, but it seems to only work when it is incremented by hand and the server is restarted.
2.Create a compiler and tell it to clean up the old assets and recompile them:
compiler = Compass::Compiler.new(
Rails.root.to_s,
Compass.configuration.sass_path,
Compass.configuration.css_path,
{:sass => Compass.sass_engine_options} )
compiler.clean!
compiler.run
With this method, however, I run into the problem that the Sprockets::Index.expire_index! method raises an error when I try to create a new compiler.
Yes, I do understand that I can set the assets to recompile on every request, but the performance hit is not something we want. Also, since this is a theme, the data should not be changing often, so we only need to recompile when the admin chooses to save the new theme.
So, finally, my question is: Are there any other possible methods to do what I want? Or am I going down the right path, and if so, where am I going wrong?
EDIT:
I forgot to mention that since we are using Sass functions to change the values of the stylesheets, even if I do turn on the option to compile in production, it won't work. Since the actual stylesheets will never change.
Rails has a Rake task that does asset compilation for you. You should run it once every time you deploy your application to your production environment.
rake assets:precompile
The compiled assets are output to public/assets. For more details, check out the Rails Asset Pipeline Guide.

How to make "assets:precompile" NOT load the database? (Rails)

I'm deploying my Rails app on Heroku (Cedar), and there were 3 options about precompiling my assets I could choose from, and I chose the option where Heroku precompiles my assets on deployment.
When I pushed, I got an error that it cannot access my database (during precompiling). So, how to make Rails not connect to the database during precompiling? I don't know why it's set in the first place, because I can't imagine a scenario where precompiling would need access to the database.
I saw somewhere a solution to disable initializing the application on precompiling, which is achieved by adding the following into the application.rb (setting it in the environments/production.rb doesn't work):
config.assets.initialize_on_precompile = false
I tried adding this line, and it works, but I don't know if it is a good solution. Wouldn't this make some plugins you would potentially use for the assets not load during precompiling, thus affecting the end result?
What you're doing is the correct way. If you don't use models / anything else which is actually accessing the database in your assets then you have no need for it. The only time you'd need to have your app initialized is if you were doing things like this: (Completely contrived example, but you can see what I'm getting at)
/* In some css file */
.some_class{
#{User.find(1).avatar_url}
}
If you enable Heroku Labs (http://devcenter.heroku.com/articles/labs-user-env-compile) you can have access to your Db at deployment time which works great.
Do you use Devise? That's usually a culprit for DB access on precompiling assets incidentally.

Am I doing something wrong with the asset pipeline?

Since "upgrading" to Rails 3.1 my app is really slow in development mode
(> 30 per request)
I have a lot of images and it seems most of this time-delay is the asset pipeline processing each GET request for each image.
Don't have this problem in Staging or Production mode as the assets are cached etc.
Is there something I haven't been told or is this how we're expected to work now?
Requests can be slow if you have gems or portions of your app that load code at the start of each request - or that merely reference portions of your app, causing much of it to be loaded. For most of these, the autoloader is the prime cause of request delay.
The rails auto-reloader deletes any autoloadable classes/modules/etc at the start of each request, and can cause significant delays at the beginning of each request as Rails reloads all the source files it needs.
You might want to try playing with https://github.com/wavii/rails-dev-tweaks, which gives you granular control over which requests cause the auto-reloader to kick in. This really isn't a fix of the root cause (something is doing extra work at the start of every request that it probably doesn't need to be doing) - but it certainly mitigates most such issues.
In the meantime:
cp -R app/assets/images public/assets
really helps
remember to add public/assets/* to .gitignore
If your app is slow it is because of your app or one of the gems that you use. I had similar issue and it looks like Mongoid was the case more you can read here:
http://martinciu.com/2011/06/rails-3-1-and-slow-asset-pipeline.html
You can use a rake task:
rake assets:precompile RAILS_ENV=development RAILS_ASSETS_NONDIGEST=true
And as it was mentioned above, don't forget to include public/assets/* to .gitignore

why might rails-2.3.5 not reload some files under app in development mode?

I've added a subdirectory app/renderers after Railscast #101. The classes in that directory are not getting reloaded by my development server. It's driving me a little bonkers.
I've read everything I could find on forcing it to reload lib and/or plugins but this seems to be a different case since "everything under app should be reloaded automatically." Plus, I've checked ActiveSupport::Dependencies.load_once_paths, and app/renderers definitely isn't in it.
I'd also like to get the renderers to be automatically required, so that I don't have to go around putting require statements in the rest of my code. Is that sensible? How does it work for, say, models and other constants?
Doh. I should have been loading the files, not requiring them.
I'd still like to have them magically loaded -- not needing a specific load statement for each one -- but for now it's working :)

Resources