The Asset Pipeline
The asset pipeline provides a framework for managing JavaScript, CSS, and images in your Rails application. Rails 7+ uses modern tools like Propshaft, Import Maps, and optionally Tailwind CSS.
Modern Rails Asset Management
Rails 7+ offers several options for managing frontend assets:
Import Maps (Default)
Import maps allow you to use JavaScript modules directly in the browser without bundling:
1# config/importmap.rb
2pin "application"
3pin "@hotwired/turbo-rails", to: "turbo.min.js"
4pin "@hotwired/stimulus", to: "stimulus.min.js"
5pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
6pin_all_from "app/javascript/controllers", under: "controllers"1// app/javascript/application.js
2import "@hotwired/turbo-rails"
3import "controllers"Adding JavaScript Libraries
1# Add a package via import maps
2bin/importmap pin lodashCSS in Rails 7+
CSS Bundling with Tailwind
Generate a new app with Tailwind:
1rails new myapp --css=tailwindOr add to existing app:
1bundle add tailwindcss-rails
2rails tailwindcss:install1<!-- app/views/layouts/application.html.erb -->
2<%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
3<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>Tailwind Configuration
1// config/tailwind.config.js
2module.exports = {
3 content: [
4 './app/views/**/*.html.erb',
5 './app/helpers/**/*.rb',
6 './app/assets/stylesheets/**/*.css',
7 './app/javascript/**/*.js'
8 ],
9 theme: {
10 extend: {
11 colors: {
12 primary: '#3B82F6',
13 secondary: '#10B981'
14 }
15 }
16 },
17 plugins: []
18}Custom CSS
1/* app/assets/stylesheets/application.css */
2@import "tailwindcss/base";
3@import "tailwindcss/components";
4@import "tailwindcss/utilities";
5
6/* Custom styles */
7@layer components {
8 .btn {
9 @apply px-4 py-2 rounded font-semibold;
10 }
11
12 .btn-primary {
13 @apply bg-blue-500 text-white hover:bg-blue-600;
14 }
15
16 .card {
17 @apply bg-white rounded-lg shadow-md p-6;
18 }
19}Image Assets
Image Tag Helper
1<%= image_tag "logo.png" %>
2<%= image_tag "hero.jpg", class: "w-full h-64 object-cover" %>
3<%= image_tag "avatar.png", alt: "User avatar", size: "50x50" %>Images in CSS
1.hero {
2 background-image: url('hero.jpg');
3}Active Storage Images
For user-uploaded images:
1<%= image_tag @user.avatar if @user.avatar.attached? %>
2<%= image_tag @user.avatar.variant(resize_to_limit: [100, 100]) %>Stimulus Controllers
Stimulus is Rails' modest JavaScript framework:
1rails generate stimulus hello1// app/javascript/controllers/hello_controller.js
2import { Controller } from "@hotwired/stimulus"
3
4export default class extends Controller {
5 static targets = ["name", "output"]
6
7 greet() {
8 this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`
9 }
10}1<!-- Using the controller -->
2<div data-controller="hello">
3 <input data-hello-target="name" type="text">
4 <button data-action="click->hello#greet">Greet</button>
5 <span data-hello-target="output"></span>
6</div>Common Stimulus Patterns
1// Toggle visibility
2import { Controller } from "@hotwired/stimulus"
3
4export default class extends Controller {
5 static targets = ["content"]
6
7 toggle() {
8 this.contentTarget.classList.toggle("hidden")
9 }
10}
11
12// Form validation
13import { Controller } from "@hotwired/stimulus"
14
15export default class extends Controller {
16 static targets = ["email", "submit"]
17
18 validate() {
19 const isValid = this.emailTarget.value.includes("@")
20 this.submitTarget.disabled = !isValid
21 }
22}Turbo for Fast Navigation
Turbo makes your app feel like a SPA without writing JavaScript:
Turbo Drive
Automatically converts links and forms to AJAX:
1<!-- Regular link - Turbo Drive intercepts this -->
2<%= link_to "Articles", articles_path %>
3
4<!-- Disable Turbo for specific link -->
5<%= link_to "External", "https://example.com", data: { turbo: false } %>Turbo Frames
Update only part of the page:
1<!-- articles/index.html.erb -->
2<%= turbo_frame_tag "articles" do %>
3 <% @articles.each do |article| %>
4 <%= render article %>
5 <% end %>
6
7 <%= link_to "Load More", articles_path(page: @page + 1) %>
8<% end %>Turbo Streams
Real-time updates:
1# articles_controller.rb
2def create
3 @article = Article.create(article_params)
4
5 respond_to do |format|
6 format.turbo_stream
7 format.html { redirect_to articles_path }
8 end
9end1<!-- app/views/articles/create.turbo_stream.erb -->
2<%= turbo_stream.prepend "articles", @article %>
3<%= turbo_stream.update "new_article_form", partial: "articles/form" %>Production Asset Compilation
1# Precompile assets for production
2rails assets:precompile
3
4# Clean old assets
5rails assets:clean
6
7# Full clean
8rails assets:clobberAsset Digest and Fingerprinting
Rails automatically adds fingerprints to assets for cache busting:
1<!-- Development -->
2<link href="/stylesheets/application.css">
3
4<!-- Production -->
5<link href="/assets/application-a1b2c3d4.css">CDN Configuration
1# config/environments/production.rb
2config.asset_host = "https://assets.example.com"Common Patterns
Conditional CSS Classes
1<div class="card <%= 'featured' if @article.featured? %>">
2 <%= @article.title %>
3</div>
4
5<%= content_tag :div, @article.title,
6 class: ['card', ('featured' if @article.featured?)] %>Dynamic Styles
1<div style="background-color: <%= @user.theme_color %>;">
2 Profile
3</div>Modern Rails asset management is simpler and more powerful than ever!
