Table of contents
1.
Introduction 💡
2.
Asset Pipeline
2.1.
Features of Asset Pipeline
3.
How to use the Asset Pipeline
3.1.
Controller Specific Assets
3.2.
Asset Organisation
3.3.
Coding Links to Assets
3.4.
Manifest Files and Directives
3.5.
Preprocessing
4.
Development Phase
4.1.
Raising Error
4.2.
Turning Off Digests
4.3.
Turning Source Maps On
5.
Production Phase
5.1.
Precompiling Assets
5.2.
Local Precompilation
5.3.
Live Compilation
5.4.
CDNs
6.
Customising the Pipeline
6.1.
CSS Compression
6.2.
JS Compression
6.3.
GZipping
7.
Asset Cache-Store
8.
Integrating Assets to your Gems
8.1.
Making your Gem Pre-Processor
9.
Frequently Asked Questions
9.1.
Is Ruby a procedural language?
9.2.
What is RubyGems?
9.3.
What is the advantage of using a pipeline?
10.
Conclusion
Last Updated: Mar 27, 2024
Hard

Asset Pipeline in Ruby on Rails

Author Manish Kumar
1 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction 💡

Hey Ninja 🥷!! We are sure you must have heard of Stylesheets, Images, and Scripts by now in your development journey. These static files are called assets. More specifically, assets are those files that require an additional request to grab. This blog will teach you about Asset Pipeline in Ruby on Rails. Let's jump right into the details. 😁
 

Asset Pipeline

Asset Pipeline

Asset Pipeline is a framework that serves three purposes: 

  • Concatenate
  • Minify 
  • Preprocess 
     

Asset Pipelines can compress Javascript and CSS files. It allows assets from our application to be automatically combined with assets from other gems. Let us study the details of the asset pipeline in ruby on rails.
 

Purpose of Asset Pipeline

 

By default, the gem sprocket-rails enable the asset pipeline. To disable, use the –skip-asset-pipeline option while creating a new application.

$ rails new app name --skip-asset-pipeline

 

To integrate the Sass into rails, use the sassc-rails gem.

gem 'sassc-rails'

 

Features of Asset Pipeline

Concatenation: Asset pipeline merges all javascript files into one master JS file and all the stylesheets into one master CSS file. In production, rails insert SHA256 fingerprint to enable browser caching.

Let's understand this using an example. Suppose you have three CSS files:
 

<html>
  <head>
    <link href="navbar.css" rel="stylesheet">
    <link href="code.css" rel="stylesheet">
    <link href="ninja.css" rel="stylesheet">
    ...
  </head>
  <body>
    ...
  </body>
</html>


The browser will make three separate requests to fetch these files, which is pretty slow. Combining all files in one master file is better than making a single request.

// application.css
/*
  navbar.css styles here
  ...
*/
/*
  code.css styles here
  ...
*/
/*
  ninja.css styles here
  ...
*/

 

Asset Pipelines does this for us, making our life easier. It happens with both JS and CSS files.
 

Minification: Minification is a standard process to shorten file size by removing unnecessary spaces and comments. Small size means more speed. 🚀

 

Normal Javascript

Input JS

 

Minified Javascript

Minified JS

 

Preprocessing

To understand preprocessing, let us go through an example: 

// navbar.scss.erb
nav {
  li {
    a {
      color: <%= color %>;
    }
  }
}

 

The direction of preprocessing is from right to left. The file is passed through the ERB processor, which would substitute in red for <%= color %>:

nav {
  li {
    a {
      color: red;
    }
  }
}

 

After this, the file is passed through the sass preprocessor. It compiles SCSS into regular CSS:

nav li a {
  color: red;
}

 

Fingerprinting

We all have unique fingerprints. The same concept is exploited for differentiating two versions of the same file. Fingerprinting is a technique by which modern applications make the name of the file dependent on the contents of the file. If the file's content changes, so do its name. 
 

When file names are unique and based on their content, it enables easy caching for CDNs, ISPs, and web browsers. When content changes, its fingerprint also changes. This allows browsers to request a new copy of the file. 

Fingerprinting

 

Asset Pipelines in Ruby on Rails uses a fingerprint by attaching hashes of content at the end of file names. For example, a CSS file ninja.css :

ninja-908e25f4bf641868d8683022a5b62f54.css

How to use the Asset Pipeline

Previously in Rails, all assets were present in the subfolders for the public directory. All javascript, stylesheets and images were present inside the public folder. With the asset pipeline, the preferred location is now the app/assets directory. These are served by Sprockets middleware.

If you still intend to use the public directory to place your assets, set the config.public_file_server.enabled property to be true. In production, Rails compiles these files to public/assets by default. These precompiled copies serve as ready static assets. 

Controller Specific Assets

When you create a controller, Rails also generates a CSS for the controller. For example, if you develop a NinjaController, Rails will add a new file at app/assets/stylesheets/ninja.scss. These files are immediately ready for consumption by the require_tree directive. 

Asset Organisation

There are three locations inside an app where assets are placed:

  • app/assets: The assets owned by the application, such as images, javascript, and CSS files, reside here
  • lib/assets: assets that are part of libraries or which are shared among applications rest here
  • vendor/assets: this is for assets owned by third parties such as plugins and frameworks. 
     

Coding Links to Assets

To use the assets, use the old-school javascript_include_tag and stylesheet_link_tag:

<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>

Manifest Files and Directives

Sprockets use manifest files to determine which files to include and serve. These manifest files contain instructions for the order of files required to build a single CSS or JS file. After requiring the files, Sprocket preprocesses, concatenates and compresses them. Rails first look at the files in the config.assets.precompile array when the task is run. By default, this array includes application.css and application.js. Let's consider application.js:


//= require jquery
//= require app
//= require_self
//= require_tree dogs
//= require_tree .
var foo = 'bar';

 

Lines prefaced by //= are called directives because they’re directing the compiler, telling it what to do.

Preprocessing

The file extensions are indicators of which preprocessing is applied. When a scaffold or controller is generated with the default rails gemset, an SCSS file is created instead of CSS. When the asset pipeline is enabled, these files are preprocessed and kept in the public/assets directory to be served by the web server.

Additional layers of preprocessing are requested by adding other extensions, where each extension is processed in the right to left direction. For example, a CSS file called app/assets/stylesheets/projects.scss.erb is processed as ERB, then SCSS, and finally served as CSS. 

Development Phase

In the development phase, assets are served in concatenated form.

The manifest app/assets/javascripts/application.js:

//= require core
//= require projects
//= require tickets

 

Will generate this HTML:

<script src="/assets/application-728742f3b9daa182fe7c831f6a3b8fa87609b4007fdc2f87c134a07b19ad93fb.js"></script>

Raising Error

In newer Sprocket versions, we can configure it to perform custom actions if asset lookup fails. If the fallback mechanism is disabled, an error is shown; otherwise, fallback to the specified path happens.

config.assets.unknown_asset_fallback = false

 

The asset fallback behaviour is disabled by default.

Turning Off Digests

We can turn off digests by updating config/environments/development.rb 

config.assets.digest = false

 

When it is set to true, digests will be generated.

Turning Source Maps On

We can turn on source maps by configuring config/environments/development.rb

config.assets.debug = true

 

Sprockets generate a source map for each asset, enabling debugging in browser developer tools.

Production Phase

In the production environment, Sprockets considers all the files to be precompiled and ready to be served. It uses the fingerprinting technique discussed above.

For example:

<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "application" %>

 

The above code generates:

<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js"></script>
<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" rel="stylesheet" >

Precompiling Assets

Rails have a command to compile assets and manifests in the pipeline. Compiled files are located at a place specified by the config.assets.prefix. By default, this is the /assets directory.

The command is :

$ RAILS_ENV=production rails assets:precompile

Local Precompilation

Sometimes you do not want to compile on the server due to certain restrictions or if you are sure these files will be static. In such cases, you can precompile the assets locally, get them in a ready state and push it to production. These files will not be compiled after getting into production.

The command is:

$ RAILS_ENV=production rails assets:precompile

Live Compilation

In some instances, you may want to compile on the fly. Sprockets directly handle all assets in this mode.

The command is:

config.assets.compile = true

CDNs

CDN extends to the Content Delivery Network. These are geographically spread servers dedicated to delivering content with low latency. They are primarily designed to cache frequently used assets; when a browser requests an asset, it is served from the closest server. If you are serving assets from your production state, it is best to put a CND in front.

 

CDN

Customising the Pipeline

Rails have a lot of customisation options for assets in the pipeline. Some of them are CSS and JS compression, gzipping and changing paths.

CSS Compression

One option to compress CSS files is by using YUI. It facilitates minification. Require the yui-compressor gem and execute the following commands:

config.assets.css_compressor = :yui

JS Compression

It is similar to CSS compression. For JS compression, use yui, terser or closure. The following line invokes a terser for JS compression.

config.assets.js_compressor = :terser

GZipping

Gzipped assets reduce the transmission of data. By default, both gzipped and non-gzipped versions of compiled assets are generated. Use the following command to configure this:

config.assets.gzip = false

Asset Cache-Store

Sprocket caches assets in the tmp/cache/assets directory in development and production environments. To change it, use the following code:

config.assets.configure do |env|
  env.cache = ActiveSupport::Cache.lookup_store(:memory_store,
                                                { size: 32.megabytes })
end

 

For disabling the cache–store:

config.assets.configure do |env|
  env.cache = ActiveSupport::Cache.lookup_store(:null_store)
end

Integrating Assets to your Gems

It is sometimes required to add assets originating from external gems. A good example is a jquery-rails gem. By adding gems to assets, we ensure Sprockets acknowledges the path of assets from external gems.

Making your Gem Pre-Processor

To extend Sprocket's functionality, Sprockets uses Processors, Transformers, Compressors and Exporters. Let's understand this through an example where we will add a comment to the end of a text/CSS file.

module AddComment
  def self.call(input)
    { data: input[:data] + "/* Hello Ninja */" }
  end
end


To register it as a preprocessor:

Sprockets.register_preprocessor 'text/css', AddComment

Frequently Asked Questions

Is Ruby a procedural language?

Ruby is an unadulterated OO language that can take on the appearance of a procedural one. It has no capabilities, just strategy calls. In a Ruby strategy, the recipient, likewise called self, is a secret contention like this in C++.

What is RubyGems?

It is a package manager for the Ruby programming language. It provides a standard format for distributing Ruby packages and maintains a server for distribution.

What is the advantage of using a pipeline?

Pipelines require zero configuration from the developer side. Everything is readily available for directly integrating into the rails application.

Conclusion

This post gave you a brief overview of Asset Pipeline in Ruby on Rails. You learned about assets and pipelines and their configuration in detail. We hope you enjoyed reading our blog on Asset Pipeline in Ruby on Rails.
 

Here are a few key websites that will aid in your exploration of Ruby on Rails.

 

Refer to our Guided Path on Coding Ninjas Studio to upskill yourself in Data Structures and AlgorithmsCompetitive ProgrammingJavaScriptSystem DesignMachine learning, and many more! But suppose you have just started your learning process and are looking for questions from tech giants like Amazon, Microsoft, Uber, etc. In that case, you must look at the problemsinterview experiences, and interview bundle for placement preparations.

Nevertheless, you may consider our paid courses to give your career an edge over others!

Do upvote our blog on Asset Pipeline in Ruby on Rails if you find it helpful and engaging!

Happy Learning!!

Thank You

 

Live masterclass