简体   繁体   中英

Rails - Asset is not present in asset pipeline when using image_tag

Goal: Using my rails app with static images in assets in production environemt

Steps:

  1. I turned my rails app to production environment.
  2. Precompiled the assets with RAILS_ENV=production rails assets:precompile
  3. Set RAILS_SERVE_STATIC_FILES environemt variable to true to enable public file server (in production.rb - config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
  4. Added line config.serve_static_assets = true to /config/application.rb

With this setup, I`ve started the server.

I have a few static images in /app/assets/images/ which precompiled versions with fingerprint filename are now in /public/assets . Examples:

  • aussen-d2fb0029a12281121a1752c599e715a8e2b3db17f1e8e18248a79a7b1ca63b91.jpg
  • hintergrund-ca80e1ae5a697c86898f3a7e107694a76dc12e54320b8ac80c58eecbffe0414a.png

So far so great.

When I use background-image: url(<%= asset_path('hintergrund') %>); in application.css.erb it successfully loads the precompiled background-image from /public/assets .

Problem: I can't access the precompiled images with my image_tags in the views! Example:

<%= image_tag("aussen") %>

Error Logs:

I, [2018-03-23T00:46:29.133381 #9289]  INFO -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682] Started GET "/" for 46.142.136.81 at 2018-03-23 00:46:29 +0100
I, [2018-03-23T00:46:29.134466 #9289]  INFO -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682] Processing by HomeController#index as HTML
I, [2018-03-23T00:46:29.136604 #9289]  INFO -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682]   Rendering home/index.html.erb within layouts/application
I, [2018-03-23T00:46:29.138267 #9289]  INFO -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682]   Rendered home/index.html.erb within layouts/application (1.5ms)
I, [2018-03-23T00:46:29.138482 #9289]  INFO -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682] Completed 500 Internal Server Error in 4ms
F, [2018-03-23T00:46:29.139546 #9289] FATAL -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682]
F, [2018-03-23T00:46:29.139635 #9289] FATAL -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682] ActionView::Template::Error (The asset "aussen" is not present in the asset pipeline.):
F, [2018-03-23T00:46:29.139798 #9289] FATAL -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682]     1: <%= image_tag("aussen", id: "home-img", alt: "Aussenansicht von Simson-Seelig") %>
[f36ff000-6261-4c2c-bfcc-4a2f80cae682]     2: <div id="home" class="content">
[f36ff000-6261-4c2c-bfcc-4a2f80cae682]     3:   <p>Alles für Simson von Simson-Seelig.</p>
[f36ff000-6261-4c2c-bfcc-4a2f80cae682]     4:   <p>Für die legendären Schwalben und alle anderen SIMSON-Modelle bieten wir Ersatzteile und Service. </p>
F, [2018-03-23T00:46:29.139867 #9289] FATAL -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682]
F, [2018-03-23T00:46:29.139930 #9289] FATAL -- : [f36ff000-6261-4c2c-bfcc-4a2f80cae682] app/views/home/index.html.erb:1:in `_app_views_home_index_html_erb__177499641769

After hours of researching, I still don't get why I can access the precompiled image in the stylesheet, but not in the view with the image_tag.

Additional information:

$ ruby --version
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-linux]

$ rails --version
Rails 5.1.4

/config/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 SimsonSeelig
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.1

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.

    # Enable rails to serve my assets
    config.serve_static_assets = true
  end
end

production.rb :

Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # Code is not reloaded between requests.
  config.cache_classes = true

  # Eager load code on boot. This eager loads most of Rails and
  # your application in memory, allowing both threaded web servers
  # and those relying on copy on write to perform better.
  # Rake tasks automatically ignore this option for performance.
  config.eager_load = true

  # Full error reports are disabled and caching is turned on.
  config.consider_all_requests_local       = false
  config.action_controller.perform_caching = true

  # Attempt to read encrypted secrets from `config/secrets.yml.enc`.
  # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
  # `config/secrets.yml.key`.
  config.read_encrypted_secrets = true

  # Disable serving static files from the `/public` folder by default since
  # Apache or NGINX already handles this.
  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

  if ENV["RAILS_LOG_TO_STDOUT"].present?
    logger           = ActiveSupport::Logger.new(STDOUT)
    logger.formatter = config.log_formatter
    config.logger = ActiveSupport::TaggedLogging.new(logger)
  end

  # Compress JavaScripts and CSS.
  config.assets.js_compressor = :uglifier
  # config.assets.css_compressor = :sass

  # Do not fallback to assets pipeline if a precompiled asset is missed.
  config.assets.compile = false

  # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb

  # Enable serving of images, stylesheets, and JavaScripts from an asset server.
  # config.action_controller.asset_host = 'http://assets.example.com'

  # Specifies the header that your server uses for sending files.
  # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX

  # Mount Action Cable outside main process or domain
  # config.action_cable.mount_path = nil
  # config.action_cable.url = 'wss://example.com/cable'
  # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  # config.force_ssl = true

  # Use the lowest log level to ensure availability of diagnostic information
  # when problems arise.
  config.log_level = :debug

  # Prepend all log lines with the following tags.
  config.log_tags = [ :request_id ]

  # Use a different cache store in production.
  # config.cache_store = :mem_cache_store

  # Use a real queuing backend for Active Job (and separate queues per environment)
  # config.active_job.queue_adapter     = :resque
  # config.active_job.queue_name_prefix = "simson-seelig_#{Rails.env}"
  config.action_mailer.perform_caching = false

  # Ignore bad email addresses and do not raise email delivery errors.
  # Set this to true and configure the email server for immediate delivery to raise delivery errors.
  # config.action_mailer.raise_delivery_errors = false

  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # the I18n.default_locale when a translation cannot be found).
  config.i18n.fallbacks = true

  # Send deprecation notices to registered listeners.
  config.active_support.deprecation = :notify

  # Use default logging formatter so that PID and timestamp are not suppressed.
  config.log_formatter = ::Logger::Formatter.new

  # Use a different logger for distributed setups.
  # require 'syslog/logger'
  # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')

  if ENV["RAILS_LOG_TO_STDOUT"].present?
    logger           = ActiveSupport::Logger.new(STDOUT)
    logger.formatter = config.log_formatter
    config.logger    = ActiveSupport::TaggedLogging.new(logger)
  end

  # Do not dump schema after migrations.
  config.active_record.dump_schema_after_migration = false
end

/config/initializers/assets.rb :

# Be sure to restart your server when you modify this file.

# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'

# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
# Add Yarn node_modules folder to the asset load path.
Rails.application.config.assets.paths << Rails.root.join('node_modules')

# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )

The asset "aussen" is not present in the asset pipeline.

Technically true because you have not aussen but you have aussen.jpg so it will be <%= image_tag("aussen.jpg") %>

Look, while you use <%= image_tag("aussen") %> then it will be genarate HTML like this

<%= image_tag("aussen") %>
#=> <img alt="Aussen" src="/assets/aussen" />

While you use <%= image_tag("aussen.jpg") %> then it will be genarate HTML like this

<%= image_tag("aussen.jpg") %>
#=> <img alt="Aussen" src="/assets/aussen.jpg" />

When it's going into production mode then it will be shown some encrypted key on the page source like this

aussen-d2fb0029a12281121a1752c599e715a8e2b3db17f1e8e18248a79a7b1ca63b91.jpg

image_tag AssetTagHelper see this for reference.

Update production.rb file config.assets.compile false to true

# config/environments/production.rb
...
config.assets.compile = true
...

Not sure if you want to set config.assets.compile = true in production, this will slow down your server

config.assets.compile=true in Rails production, why not?

Instead of explicitly setting config.assets.compile = false. Comment it out that worked for me, this is probably a bug. After commenting this out images were correctly rendered using the precompiled asset pipeline.

# config.assets.compile = false

I had this same issue when working on a Rails 6 application in Ubuntu 20.04 .

The issue for me was that I had not precompiled the assets in production.

Here's how I fixed it :

First, I ran the command below to precompile the assets and make them available in the public directory of my application:

rails assets:precompile RAILS_ENV=production

Note : In development this can be accomplished using webpacker with the command: /bin/webpack-dev-server

Next, set up Nginx or Apache web server to serve the static files that are available in the public directory of my application. For me I set up Nginx with the configuration below using Let's Encrypt for SSL:

upstream railsserver {
        server 127.0.0.1:3000;
}

server {

        # Replace 'localhost' with your FQDN if you want to use
        # your app from remote or if you need to add a certificate 
        server_name my-website.com www.my-website.com;
                        
        root /home/deploy/my-website/public;

        # Define where Nginx should write its logs
        access_log /var/log/nginx/my-website/access.log;
        error_log /var/log/nginx/my-website/error.log;

        location / {
            # First attempt to serve request as file, then
            # the rails application directory
            try_files $uri @railsserver;
        }
       
        location ~ ^/(assets/|robots.txt|humans.txt|favicon.ico) {
                expires max;
        }

        location @railsserver {
                proxy_set_header Host $http_host;
                proxy_set_header CLIENT_IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_read_timeout 300;
                proxy_pass http://railsserver;

                gzip on;
                gzip_types text/plain text/xml text/css image/svg+xml application/javas$
                gzip_proxied any;
        }

        listen [::]:443 ssl ipv6only=on; # managed by Certbot
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/my-website.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/my-website.com/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

That's all.

I hope this helps

如果链接不明确,可以参考这个:

image_tag '#', skip_pipeline: true

This is the answer when none of the above work.

Are you referencing a .jpeg file? .jpeg files get compiled to .jpg files and so if you reference .jpeg you will get this error.

The solution is to rename the file to .jpg and reference the image_tag with the corresponding .jpg extension.

It can also happen if your images are in the wrong place. For rails 6, place images inside /app/assets/images/ , then simply

<%= image_tag("logo1.png", alt: "My logo", size: '200x75') %>

If it happens when using video_tag with ActiveStorage, this should work:

<%= video_tag url_for(@banner_video.file), size: "150x120", controls: true %>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM