Rails - 在生产模式下找不到application.css资源

36

我正在升级一个应用程序以使用资产管道。

我已将 CSS 资源编译到应用程序 CSS 文件中,但当我在生产模式下运行应用程序时,它们无法被找到。

RAILS_ENV=production bundle exec rails s

当我访问任何页面时,我可以从数据库中获得正确的输出,但没有样式,日志显示:

ActionController::RoutingError (No route matches [GET] 
"/assets/default.scss-1a27c...f07c.css"):
尽管该文件存在于public/assets目录中。
$ ls public/assets/def*
public/assets/default.scss-1a27c...f07c.css     public/assets/default.scss.css
public/assets/default.scss-1a27c...f07c.css.gz  public/assets/default.scss.css.gz

我需要修改什么来让服务器找到资源文件?

我的其他.css文件也是一样的情况。它们被编译成带有指纹的public/assets,但是找不到。

页面源代码显示:

<link href="/assets/default.scss-1a27c...f07c.css" 
media="screen" rel="stylesheet" type="text/css" />

在 Rails(Haml)源代码中,有如下代码:= stylesheet_link_tag 'default.scss.css'

public.assets 目前包含以下文件。

$ ls public/assets/def*
public/assets/default.scss-1a27c22229b7b522066181f27af4f07c.css
public/assets/default.scss-1a27c22229b7b522066181f27af4f07c.css.gz
public/assets/default.scss.css
public/assets/default.scss.css.gz

application.rb文件有

$ cat config/application.rb 
require File.expand_path('../boot', __FILE__)

# Pick the frameworks you want:
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "sprockets/railtie"
# require "rails/test_unit/railtie"

if defined?(Bundler)
  # If you precompile assets before deploying to production, use this line
  Bundler.require(*Rails.groups(:assets => %w(development test)))
  # If you want your assets lazily compiled in production, use this line
  # Bundler.require(:default, :assets, Rails.env)
end

module Linker
  class Application < Rails::Application
    config.encoding = "utf-8"
    config.filter_parameters += [:password]
    config.assets.enabled = true
    config.assets.initialize_on_precompile = false # For Heroku
    config.assets.version = '1.0'
  end
end

config/environments/production 包含以下内容:

$ cat config/environments/production.rb 
Linker::Application.configure do
  config.consider_all_requests_local       = false
  config.action_controller.perform_caching = true
  config.assets.precompile += ['default.scss.css','main.css', 'jquery-ui-1.8.22.custom.css']
  config.serve_static_assets = false
  config.assets.compress = true
  config.assets.compile = false
  config.assets.digest = true
  config.log_level = :debug
  config.i18n.fallbacks = true
  config.active_support.deprecation = :notify
end

这似乎是所有资产都发生的情况,例如:

Started GET "/assets/default.scss-1a27c22229b7b522066181f27af4f07c.css" for 127.0.0.1 at 2014-02-23 10:24:47 -0500
ActionController::RoutingError (No route matches [GET] "/assets/default.scss-1a27c22229b7b522066181f27af4f07c.css"):
Started GET "/assets/main-6864687b4114a1c316e444bd90f233ff.css" for 127.0.0.1 at 2014-02-23 10:24:47 -0500
ActionController::RoutingError (No route matches [GET] "/assets/main-6864687b4114a1c316e444bd90f233ff.css"):
Started GET "/assets/jquery-ui-1.8.22.custom-24319b4b1218846a3fe22a0479ae98b4.css" for 127.0.0.1 at 2014-02-23 10:24:47 -0500
ActionController::RoutingError (No route matches [GET] "/assets/jquery-ui-1.8.22.custom-24319b4b1218846a3fe22a0479ae98b4.css"):
Started GET "/assets/application-fc1d492d730f2a45581a40eac4607db8.js" for 127.0.0.1 at 2014-02-23 10:24:47 -0500
ActionController::RoutingError (No route matches [GET] "/assets/application-fc1d492d730f2a45581a40eac4607db8.js"):
Started GET "/images/link.ico" for 127.0.0.1 at 2014-02-23 10:24:48 -0500
ActionController::RoutingError (No route matches [GET] "/images/link.ico"):

1
你执行了 rake assets:precompile 吗? - Raj
是的,我执行了 $ RAILS_ENV=production bundle exec rake assets:precompile 命令并重启了服务器。 - Michael Durrant
1
你能复制你的application.rb和production.rb文件吗? - arieljuod
检查一下这个问题和答案,你似乎有错误的名称。https://dev59.com/x2s05IYBdhLWcg3wPPaB - arieljuod
4个回答

44
默认情况下,Rails 不会在 public 目录下提供资产服务。请查看您的 production.rb 文件:
  config.serve_static_assets = true

将其更改为true,您就可以开始了。 (注意:在生产中,您不希望它是true,请记得在部署之前将其更改回来!)
有关详细信息,请参见配置Rails应用程序在Rails 6中,在默认的production.rb中应该有一行。
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

因此,请使用以下命令运行您的服务器:

RAILS_SERVE_STATIC_FILES=true rails server -e production

或在production.rb中设置config.public_file_server.enabled=true。有关Rails 4和5的答案,请参见下面的答案。


3
为什么这在生产环境中会是错误的?我正在使用rails_12factor和heroku。谢谢您的进一步解释! - Leo Folsom
3
Rails假设在生产环境中,在Rails之前有一个Web服务器(Apache、nginx)运行,甚至为静态资源专门提供CDN。其中任何一个都可以比Rails更快地提供静态资源。 - awendt
7
针对Rails 5版本:在config/environments/production.rb文件中,将config.public_file_server.enabled设为true,以开启公共文件服务器。 - vmarquet
2
@vmarquet,我刚刚花了太多时间搜寻这个答案...在生产模式下使用 <%= link_to('Logout', destroy_user_session_path, method: :delete) %>带到了这里,给那些不可避免会跟随的人一个提示。谢谢! - Victor Ude
3
我来翻译一下:在Rails 5中,通过 ENV['RAILS_SERVE_STATIC_FILES'].present? 来设置配置标志。这意味着你可以使用 RAILS_SERVE_STATIC_FILES=1 rails server --environment production 命令运行服务器,而无需更改配置文件。 - Glutexo
@awendt 我在后端网络工作方面还比较新(其他方面有经验),如果您能详细解释一下您在这里的评论,我会非常感激。听起来这可能是一本书的重点。您是说我需要在同一台机器上同时运行apache和rails,以分别为网站的不同部分提供服务,静态资源与rails生成的html? - temporary_user_name

12
Rails 5的解决方案与Jules Copeland在上面提供的Rails 4 solution类似。在您预先生成的config/environments/production.rb文件中,应该有一个条目看起来像这样:
# 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?

我在配置Rails应用程序指南 http://guides.rubyonrails.org中找到了一个不错的解释:config.public_file_server.enabled配置Rails从public目录提供静态文件。此选项默认为true,但在生产环境中将其设置为false,因为运行应用程序的服务器软件(例如NGINX或Apache)应该提供静态文件。如果您在生产模式下使用WEBrick运行或测试应用程序(不建议在生产中使用WEBrick),请将选项设置为true。否则,您将无法使用页面缓存并请求存在于public目录下的文件。

结论:在生产环境中,使用RAILS_SERVE_STATIC_FILES=1启动你的Rails服务器将允许Rails像Web服务器一样提供public/assets目录中的任何文件。请记住,Rails是一个应用程序服务器,并不像Web服务器(如NGINX、Apache等)那样高效地执行此操作。对于真实世界的应用程序,你应该有一个专用的Web服务器坐在Rails前面,它将自己服务静态资源,并只在需要时打扰Rails获取动态内容。有关Web服务器和应用服务器之间差异的详细信息,请参见Justin Weiss的this article


10
在Rails 4中,您可以通过传递一个环境变量来在生产环境(本地运行)中展示它们: RAILS_SERVE_STATIC_FILES=true rails server -e production 只要在/config/environments/production.rb中有以下行: config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?, 就应该可以正常工作。

4
当你执行rake assets:precompile命令时,你的资产将被放置在公共目录中。请查看public/assets/目录下是否存在这些文件。
你应该会看到如下内容:
I, [2014-02-23T20:06:21.853314 #26915]  INFO -- : Writing app_root/public/assets/application-ecd8636fc80ea2b712039c4abc365da9.css

1
预编译时,它会写入哪个目录? - Raj
+1 感谢。看起来它至少是写入到 public/assets 目录,那里有指纹文件。 - Michael Durrant
1
新写的文件名和被请求的文件名是否匹配? - Raj
我在问题中添加了更多来自public/assets的输出。 - Michael Durrant
好的,嗯,这给了我 (No route matches [GET] "/assets/default.scss-1a27c22229b7b522066181f27af4f07c.css"): - Michael Durrant
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接