ActionView::Template::Error (The asset "tailwind.css" is not present in the asset pipeline.

Hi all, I am trying to deploy my rails project with flyctl deploy and it deploys fine, but the logs show

ActionView::Template::Error (The asset “tailwind.css” is not present in the asset pipeline.

I can run fly ssh console and find that tailwind.css file in app/assets/builds just fine and I cannot seem to find the solution to this.

Dockerfile:
Here is my Dockerfile

# syntax = docker/dockerfile:experimental

# Dockerfile used to build a deployable image for a Rails application.
# Adjust as required.
#
# Common adjustments you may need to make over time:
#  * Modify version numbers for Ruby, Bundler, and other products.
#  * Add library packages needed at build time for your gems, node modules.
#  * Add deployment packages needed by your application
#  * Add (often fake) secrets needed to compile your assets

#######################################################################

# Learn more about the chosen Ruby stack, Fullstaq Ruby, here:
#   https://github.com/evilmartians/fullstaq-ruby-docker.
#
# We recommend using the highest patch level for better security and
# performance.

ARG RUBY_VERSION=2.7.2
ARG VARIANT=jemalloc-slim
FROM quay.io/evl.ms/fullstaq-ruby:${RUBY_VERSION}-${VARIANT} as base

LABEL fly_launch_runtime="rails"

ARG NODE_VERSION=16.15.1
ARG YARN_VERSION=1.22.17
ARG BUNDLER_VERSION=2.1.4

ARG RAILS_ENV=production
ENV RAILS_ENV=${RAILS_ENV}

ENV RAILS_SERVE_STATIC_FILES true
ENV RAILS_LOG_TO_STDOUT true

ARG BUNDLE_WITHOUT=development:test
ARG BUNDLE_PATH=vendor/bundle
ENV BUNDLE_PATH ${BUNDLE_PATH}
ENV BUNDLE_WITHOUT ${BUNDLE_WITHOUT}

RUN mkdir /app
WORKDIR /app
RUN mkdir -p tmp/pids

RUN curl https://get.volta.sh | bash
ENV VOLTA_HOME /root/.volta
ENV PATH $VOLTA_HOME/bin:/usr/local/bin:$PATH
RUN volta install node@${NODE_VERSION} yarn@${YARN_VERSION} && \
    gem update --system --no-document && \
    gem install -N bundler -v ${BUNDLER_VERSION}

#######################################################################

# install packages only needed at build time

FROM base as build_deps

ARG BUILD_PACKAGES="git build-essential libpq-dev wget vim curl gzip xz-utils libsqlite3-dev"
ENV BUILD_PACKAGES ${BUILD_PACKAGES}

RUN --mount=type=cache,id=dev-apt-cache,sharing=locked,target=/var/cache/apt \
    --mount=type=cache,id=dev-apt-lib,sharing=locked,target=/var/lib/apt \
    apt-get update -qq && \
    apt-get install --no-install-recommends -y ${BUILD_PACKAGES} \
    && rm -rf /var/lib/apt/lists /var/cache/apt/archives

#######################################################################

# install gems

FROM build_deps as gems

COPY Gemfile* ./
RUN bundle install &&  rm -rf vendor/bundle/ruby/*/cache

#######################################################################

# install node modules

FROM build_deps as node_modules

COPY package*json ./
COPY yarn.* ./
RUN yarn install

#######################################################################

# install deployment packages

FROM base

ARG DEPLOY_PACKAGES="postgresql-client file vim curl gzip libsqlite3-0"
ENV DEPLOY_PACKAGES=${DEPLOY_PACKAGES}

RUN --mount=type=cache,id=prod-apt-cache,sharing=locked,target=/var/cache/apt \
    --mount=type=cache,id=prod-apt-lib,sharing=locked,target=/var/lib/apt \
    apt-get update -qq && \
    apt-get install --no-install-recommends -y \
    ${DEPLOY_PACKAGES} \
    && rm -rf /var/lib/apt/lists /var/cache/apt/archives

# copy installed gems
COPY --from=gems /app /app
COPY --from=gems /usr/lib/fullstaq-ruby/versions /usr/lib/fullstaq-ruby/versions
COPY --from=gems /usr/local/bundle /usr/local/bundle

# copy installed node modules
COPY --from=node_modules /app/node_modules /app/node_modules

#######################################################################

# Deploy your application
COPY . .

# Adjust binstubs to run on Linux and set current working directory
RUN chmod +x /app/bin/* && \
    sed -i 's/ruby.exe/ruby/' /app/bin/* && \
    sed -i '/^#!/aDir.chdir File.expand_path("..", __dir__)' /app/bin/*

# The following enable assets to precompile on the build server.  Adjust
# as necessary.  If no combination works for you, see:
# https://fly.io/docs/rails/getting-started/existing/#access-to-environment-variables-at-build-time
ENV SECRET_KEY_BASE 1
# ENV AWS_ACCESS_KEY_ID=1
# ENV AWS_SECRET_ACCESS_KEY=1

# Run build task defined in lib/tasks/fly.rake
ARG BUILD_COMMAND="bin/rails fly:build"
RUN ${BUILD_COMMAND}

# Default server start instructions.  Generally Overridden by fly.toml.
ENV PORT 8080
ARG SERVER_COMMAND="bin/rails fly:server"
ENV SERVER_COMMAND ${SERVER_COMMAND}
CMD ${SERVER_COMMAND}

fly.toml:

# fly.toml file generated for workaholic on 2022-11-08T17:20:08-05:00

app = "workaholic"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[build]
  [build.args]
    BUILD_COMMAND = "bin/rails fly:build"
    SERVER_COMMAND = "bin/rails fly:server"

[deploy]
  release_command = "bin/rails fly:release"

[env]
  PORT = "8080"

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

[[statics]]
  guest_path = "/app/public"
  url_prefix = "/"

.dockerignore:

.git
tmp
!tmp/pids
log
public/assets
public/packs
.bundle

db/*.sqlite3
db/*.sqlite3-*

storage
config/master.key
config/credentials/*.key

node_modules

Gemfile:

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "2.7.2"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.0.3", ">= 7.0.3.1"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", "~> 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]
gem "tailwindcss-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
# gem "redis", "~> 4.0"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Sass to process CSS
# gem "sassc-rails"

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

gem 'devise'

gem "heroicon"

group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "debug", platforms: %i[ mri mingw x64_mingw ]
end

group :development do
  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem "web-console"
  gem "hotwire-livereload"

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  # gem "rack-mini-profiler"

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem "spring"
end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "selenium-webdriver"
  gem "webdrivers"
end

gem "acts_as_list", "~> 1.0"

application.rb

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Workaholic
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 7.0

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")
  end
end

fly.rake

# commands used to deploy a Rails application
namespace :fly do
  # BUILD step:
  #  - changes to the filesystem made here DO get deployed
  #  - NO access to secrets, volumes, databases
  #  - Failures here prevent deployment
  task :build => 'assets:precompile'

  # RELEASE step:
  #  - changes to the filesystem made here are DISCARDED
  #  - full access to secrets, databases
  #  - failures here prevent deployment
  task :release => 'db:migrate'

  # SERVER step:
  #  - changes to the filesystem made here are deployed
  #  - full access to secrets, databases
  #  - failures here result in VM being stated, shutdown, and rolled back
  #    to last successful deploy (if any).
  task :server => :swapfile do
    sh 'bin/rails server'
  end

  # optional SWAPFILE task:
  #  - adjust fallocate size as needed
  #  - performance critical applications should scale memory to the
  #    point where swap is rarely used.  'fly scale help' for details.
  #  - disable by removing dependency on the :server task, thus:
  #        task :server do
  task :swapfile do
    sh 'fallocate -l 512M /swapfile'
    sh 'chmod 0600 /swapfile'
    sh 'mkswap /swapfile'
    sh 'echo 10 > /proc/sys/vm/swappiness'
    sh 'swapon /swapfile'
  end
end

That’s the source file. Can you verify that you have a compiled version? Here’s what I see on my app:

find . -name tailw*.css
./public/assets/tailwind-5146aee928b28afaac2c45702cb895da9e08ffa516864007783ebac005938e39.css
./app/assets/builds/tailwind.css

The public:assets directory should be set up by the assets:precompile step. This looks to be set up correctly in your Dockerfile and lib/tasks/fly.rake.

Hello everyone!

First I need to tell that I’m completely beginner in the web filed (I came from the hardware develpment world)! I’m trying to learning by myself and sorry if some questions seems very fool.
I did not open a new thread in the community because I had exactly the same problem.
My app was correctly deployed but this error “ActionView::Template::Error (The asset “tailwind.css” is not present in the asset pipeline.” persists. When I log into the server with ssh and try ‘find . -name tailw*.css’ nothing is found, but if I run ‘bundle exec rake assets:precompile’ the two files are created, but the error ActionView… persists.

The strange thing to me is that if I log out and ssh again, the css files disappear and ‘find . -name tailw*.css’ doesnt returns the files.

here are my files:
Dockerfile

# syntax = docker/dockerfile:1

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=3.2.2
FROM ruby:$RUBY_VERSION-slim as base

LABEL fly_launch_runtime="rails"

# Rails app lives here
WORKDIR /rails

# Set production environment
ENV BUNDLE_DEPLOYMENT="1" \
    BUNDLE_PATH="/usr/local/bundle" \
    BUNDLE_WITHOUT="development:test" \
    RAILS_ENV="production"

# Update gems and bundler
RUN gem update --system --no-document && \
    gem install -N bundler


# Throw-away build stage to reduce size of final image
FROM base as build

# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential curl libpq-dev libvips node-gyp pkg-config python-is-python3

# Install JavaScript dependencies
ARG NODE_VERSION=10.19.0
ARG YARN_VERSION=1.22.21
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-build-master

# Install application gems
COPY --link Gemfile Gemfile.lock ./
RUN bundle install && \
    bundle exec bootsnap precompile --gemfile && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git

# Install node modules
COPY --link .yarnrc package.json yarn.lock ./
COPY --link .yarn/releases/* .yarn/releases/
RUN yarn install --frozen-lockfile

# Copy application code
COPY --link . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Adjust binfiles to be executable on Linux
RUN sed -i "s/\r$//g" bin/* && \
    sed -i 's/ruby\r/ruby/' bin/* && \
    sed -i 's/ruby\.exe\r$/ruby/' bin/*

ARG RAILS_MASTER_KEY
# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_WITHOUT="development:test" \
    BUNDLE_DEPLOYMENT="1" \
    RAILS_MASTER_KEY=${RAILS_MASTER_KEY}


# Final stage for app image
FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl imagemagick libsqlite3-0 libvips postgresql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
    useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
    chown -R 1000:1000 db log storage tmp
USER 1000:1000

# Entrypoint sets up the container.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]

fly.toml

app = 'learning-to'
primary_region = 'gig'
console_command = '/rails/bin/rails console'

[build]

[deploy]
  #release_command = "./bin/rails db:prepare"
  release_command = "sh release.sh"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0
  processes = ['app']

[[vm]]
  cpu_kind = 'shared'
  cpus = 1
  memory_mb = 1024

[[statics]]
  guest_path = '/rails/public'
  url_prefix = '/'

release.sh

#!/usr/bin/env sh

./bin/rails db:prepare && ./bin/rails db:seed && bundle exec rake assets:precompile

The problem is that you are running this on the release machine. And it is clear that you did this as an intentional choice - I can tell you that that won’t work and why, and how you can correct this.

Is it fair to assume that the reason why you did this is because you access secrets in your configuration? If so, there are three basic approaches towards solving this:

  • Existing Rails Apps · Fly Docs describes two approaches, the first involving adding if statements, and the latter involves moving the assets:precompile from the build step to deploy (rather than release which is where you currently have it).
  • Build Secrets · Fly Docs describes a more comprehensives solution that enables you to access application secrets at build time. If you are interested, I can show you how you can package all this up as a rake task so that you can run rails deploy and all of this will be taken care of for you.

Now for the full explanation. There are three stages, each run on a separate VM: build, release, and deploy. The build step doesn’t normally have access to your secrets (but the second link above shows you how you can do this), and builds an image that is pushed to a repository. The second step runs that image, with full access to secrets, and then the ephemeral machine stopped - so any changes you make to external databases will remain but any changes you make to the file system will be lost. The deploy step starts with the image that was produced by the build step, and that’s why you can’t see the files produced by assets:precompile.

Oh rubys, thank you by your explanations, but I still have some questions:

Is this approach means to create a file config/initializers/stripe.rb, put " Stripe.api_key = Rails.application.credentials.stripe[:secret_key] as well as insert gem 'stripe' into my Gemfile, run “blundle install” and then generate a Dockerfile that will run assests:precompile at deployment time with the following command
bin/rails generate dockerfile --precompile=defer?

Sorry, but, I don’t know how to do that. How you know that my command bundle exec rake assets:precompile (Is it correct assume that when you say assests:precompile you are talking about the entire command shown before?) is in ‘release’ instead of ‘deploy’?
I’m saying this because in my ‘fly.toml’ file the call for the command mentioned before is inside the [deploy] field.

This is quite interesting, but I did something like this here in my Dockerfile, isn’t it?

ARG RAILS_MASTER_KEY
# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_WITHOUT="development:test" \
    BUNDLE_DEPLOYMENT="1" \
    RAILS_MASTER_KEY=${RAILS_MASTER_KEY}

Here I passed RAILS_MASTER_KEY as argument in fly deploy --build-arg RAILS_MASTER_KEY=$(cat config/master.key) .
I thought that would be necessary to pass only the master.key content so rails application can decrypt the config/credentials.yml.enc.

And last but not least; How this problem ActionView::Template::Error (The asset "tailwind.css" is not present in the asset pipeline. could be linked with secrets?

Again, thank you very very much!!! Because I am absolutely rookie in this field and some questions are answered by people that normally assumes the user have some knowledge, but I have not, I am an electronic engineer trying to do some effort to learn web development.

Let me start over.

If you run bin/rails generate dockerfile and accept the changes, and restore your release command to be "./bin/rails db:prepare", what error do you see?

I don’t see any errors. The deploy happens successfully, but when I try to access my application, from the browser I get an error like this:

And the fly log shows:

2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info]I, [2024-02-14T22:58:06.183160 #306]  INFO -- : [65a168bd-81fd-4874-bfc8-109d360b04b8] Completed 500 Internal Server Error in 55ms (ActiveRecord: 15.9ms | Allocations: 11216)
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info]E, [2024-02-14T22:58:06.184266 #306] ERROR -- : [65a168bd-81fd-4874-bfc8-109d360b04b8]
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8] ActionView::Template::Error (The asset "tailwind.css" is not present in the asset pipeline.
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info]):
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]      5:     <meta name="viewport" content="width=device-width,initial-scale=1">
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]      6:     <%= csrf_meta_tags %>
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]      7:     <%= csp_meta_tag %>
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]      8:     <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]      9:     <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]     10:
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]     11:     <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8]
2024-02-14T22:58:06Z app[6e82dd94c62958] gig [info][65a168bd-81fd-4874-bfc8-109d360b04b8] app/views/layouts/application.html.erb:8

That would indicate that assets:precompile wasn’t in your Dockerfile. Can you check?

bin/rails generate dockerfile will generate a Dockerfile that includes assets:precompile unless your rails application is api only.

Yes! It’s true! The assets:precompile isn’t in the Docerfile. Where i can put this "assets:precompile"?

Some like this?
RUN bundle exec rake RAILS_ENV=production assets:precompile? Is it sufficient?

I found this example: Precompile Ruby on Rails assets with Docker · GitHub

I would recommend running the following command:

bin/rails generate dockerfile --force

This will replace your Dockerfile with one that runs assets:precompile correctly.