Rails应用在生产环境中无法提供资产服务

49

我的应用在开发环境下运行良好。但是在生产环境下(rails server -e production),浏览器无法访问css和js文件,并且控制台上会显示如下信息:

I, [2013-07-27T21:00:59.105459 #11449]  INFO -- : Started GET "/javascripts/application.js" for 99.102.22.124 at 2013-07-27 21:00:59 +0000
F, [2013-07-27T21:00:59.108302 #11449] FATAL -- : 
ActionController::RoutingError (No route matches [GET] "/javascripts/application.js"):

生产环境下的html源文件中的head部分:

<head>
  <title>a Social Server</title>
  <link data-turbolinks-track="true" href="/stylesheets/application.css" media="all" rel="stylesheet">
  <link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
  <script data-turbolinks-track="true" src="/javascripts/application.js"></script>
  <meta content="authenticity_token" name="csrf-param">
<meta content="jYM4IAXTXAuKWeD4FEVrXgXRNFeB6EazU68ZBQfRqNY=" name="csrf-token">
</head>

在开发环境中,头部部分看起来如下:

<head>
  <title>a Social Server</title>
  <link data-turbolinks-track="true" href="/assets/application.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/twitter-bootstrap-static/bootstrap.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/twitter-bootstrap-static/fontawesome.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/bootstrap_and_overrides.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/instagram.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/socialserver.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.core.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.theme.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.accordion.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.menu.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.autocomplete.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.button.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.datepicker.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.resizable.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.dialog.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.progressbar.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.selectable.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.slider.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.spinner.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.tabs.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.tooltip.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.base.css?body=1" media="all" rel="stylesheet">
<link data-turbolinks-track="true" href="/assets/jquery.ui.all.css?body=1" media="all" rel="stylesheet">
  <link href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
  <script data-turbolinks-track="true" src="/assets/jquery.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery_ujs.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-transition.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-alert.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-modal.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-dropdown.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-scrollspy.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-tab.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-tooltip.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-popover.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-button.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-collapse.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-carousel.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-typeahead.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap/bootstrap-affix.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/twitter/bootstrap.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/turbolinks.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/bootstrap.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.core.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.widget.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.accordion.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.position.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.menu.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.autocomplete.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.button.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.datepicker.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.mouse.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.draggable.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.resizable.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.dialog.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.droppable.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-blind.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-bounce.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-clip.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-drop.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-explode.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-fade.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-fold.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-highlight.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-pulsate.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-scale.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-shake.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-slide.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.effect-transfer.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.progressbar.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.selectable.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.slider.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.sortable.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.spinner.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.tabs.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.tooltip.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/jquery.ui.all.js?body=1"></script>
<script data-turbolinks-track="true" src="/assets/application.js?body=1"></script>
  <meta content="authenticity_token" name="csrf-param">
<meta content="jYM4IAXTXAuKWeD4FEVrXgXRNFeB6EazU68ZBQfRqNY=" name="csrf-token">
</head>

该应用程序不使用数据库,因此我已禁用ActiveRecord。以下是配置文件的片段:

application.rb

require File.expand_path('../boot', __FILE__)
#require 'rails/all'
require "action_controller/railtie"
require "action_mailer/railtie"
require "rails/test_unit/railtie"
require "sprockets/railtie"
Bundler.require(:default, Rails.env)
module Socialserver
  class Application < Rails::Application
  end
end

生产环境配置文件

Socialserver::Application.configure do
   config.cache_classes = true
   config.eager_load = true
   config.consider_all_requests_local       = false
   config.action_controller.perform_caching = true
   config.serve_static_assets = false
   config.assets.js_compressor = :uglifier
   config.assets.compile = false
   config.assets.digest = true
   config.assets.version = '1.0'
   config.log_level = :info
   config.i18n.fallbacks = true
   config.active_support.deprecation = :notify
   config.log_formatter = ::Logger::Formatter.new
   config.assets.paths << Rails.root.join('app', 'assets', 'fonts')
   config.assets.precompile += %w( .svg .eot .woff .ttf )
end

开发.rb:

Socialserver::Application.configure do
  config.cache_classes = false
  config.eager_load = false
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false
  config.action_mailer.raise_delivery_errors = false
  config.active_support.deprecation = :log
  config.assets.debug = true
end

Gemfile:

source 'https://rubygems.org'
gem 'rails', '4.0.0'
gem 'sass-rails', '~> 4.0.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 1.2'
group :doc do
  gem 'sdoc', require: false
end
group :twitter do
  gem 'twitter', '4.8.1'
end
group :instagram do
  gem 'instagram', '0.10.0'
end
group :tumblr do
  gem 'tumblr_client'
end
gem 'twitter-bootstrap-rails'
gem 'therubyracer' #needed for runtime js on amazon ec2.

对于发布大量信息,我感到抱歉。我觉得这些信息可能是相关的。

附言:我只对Rails有一知半解,所以请见谅。谢谢~


我在升级到Rails 4的项目中遇到了类似的问题。这里提供的解决方案都没有解决它。图片和JavaScript文件都能正常服务,但CSS文件不能。CSS文件已经编译完成,出现在public/assets目录和清单文件中,但生产服务器仍然给我返回CSS文件错误。如果有人有任何想法,我很乐意知道。 - Lonny Eachus
8个回答

76

在本地测试生产环境时,您需要在本地编译资产。只需运行以下命令:

RAILS_ENV=production bundle exec rake assets:precompile

它将在public/assets下生成所有资产。

接下来,您需要告诉Rails自己提供这些资产。像Heroku这样的环境中,服务器软件(如Nginx或Apache)会为您完成此操作,但在本地环境中,您应该让Rails处理。在production.rb文件中更改此设置:

config.serve_static_assets = true

但在将代码推向生产环境之前,请确保将其设置回false


我正在尝试在 ec2 机器上自己部署这个应用程序。在 ec2 上,我安装了 ruby、rails,然后执行了 "rails server -e production" 命令。所以我猜仅仅告诉 rails 服务器命令环境是生产环境并不会导致它编译资产文件。顺便说一下,如果我在 production.rb 中设置 config.assets.compile = true,则一切正常工作。那么如果你想自己部署一个应用程序,最好的方法是什么?如果我使用 unicorn 而不是 webrick,会有什么区别吗? - septerr
1
告诉Rails环境是生产环境并不会编译资产。您需要在本地预编译它们。您可能想查看这篇文章,了解如何使用gem asset_sync将您的资产推送到S3和Cloudfront:http://blog.firmhouse.com/complete-guide-to-serving-your-rails-assets-over-s3-with-asset_sync - jibai31
如果服务器软件(例如Nginx或Apache)为我做这件事,那么在我的理解中,这意味着在服务器端将其设置为TRUEconfig.serve_static_assets = true),但是为什么在推送到服务器之前我应该将其设置回FALSE - Papouche Guinslyzinho
Papouche,我相信他们的意思是Nginx或Apache会直接从配置的位置提供资源,而无需使用Rails。也就是说,Rails负责处理非资源请求,这样用户不必等待复杂的应用框架来提供图片。Nginx和Apache已经可以轻松地提供静态文件。 - Adam Prescott
2
对于Rails 4,它将是config.serve_static_filesconfig.serve_static_assets已被弃用,并将在Rails 5中删除。 - sampi
为了不改变 config.serve_static_files 的值,你可以定义环境变量 RAILS_SERVE_STATIC_FILES - h7r

40
这听起来像是我曾经遇到的问题
我找到了一篇博客文章,建议这是Rails 4.0.0资产管道中的一个错误,并且通过设置...不可解释地得到了缓解。
config.assets.compile = true

...在config/environments/production.rb中。

除了某种方式启动资产管道以实际工作之外,该设置将打开资产的实时编译。在生产环境中,这通常是性能不佳的坏事,但如果您仍然手动预编译资产,则可以使用此设置。

rake assets:precompile

……不应该进行现场编译(因为必要的资产已经预先编译好了)。

希望这可以帮到您 :)


1
也适用于4.2版本。这可能为我节省了好几个小时的痛苦 - 谢谢! - Jules Copeland

13

如之前所述,config.serve_static_assets已被弃用,取而代之的是config.serve_static_files。如果查看Rails-4.2中的config/environments/production.rb,则会发现以下内容:

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

这意味着在运行rails s -e production之前,在一个会话中设置和导出(在BASH中)环境变量export RAILS_SERVE_STATIC_FILES="to any value whatsoever"将在本地测试时产生所需的结果,并避免在推送到生产主机之前记得重新编码production.rb


7
在production.rb中更改以下设置:

rails 3.x

config.serve_static_assets = true

rails 4.x

config.serve_static_files = true

我猜它是针对Rails 3的特定内容。 - Rui Andrada

5

检查是否存在这样的文件:

public/assets/.sprockets-manifest-3f7771d777ceb581d754e4fad88aa69c.json

如果您正在将预编译的资产推送至生产服务器,则有可能阻止隐藏的“点”文件被推送,从而导致该关键文件无法进入生产环境。在我的环境中,我需要在集成环境中预编译资产并将其推送到生产环境中,以便无需在生产机器上编译资产。我错误地阻止了所有隐藏文件被推送到生产机器。要查看此答案是否适用于您,请在生产服务器上从浏览器中检查生成的HTML源代码,以查看是否已生成资产路径。如果您看到您的脚本标记如下所示:
<script data-turbolinks-track="true" src="/javascripts/application.js"></script>

请检查src属性。它应该以/assets/javascript开头。在这种情况下,它以/javascript开头,这表明Rails认为没有预编译任何资产。
我通过更新我的推送到生产环境(目前是rsync),确保在我的集成服务器上预编译后推送.sprockets-manifest*文件来纠正这个问题。
另外,我使用独立的Passenger作为我的集成测试服务器,而不是Webrick,因为它可以更真实地提供静态文件服务。

5

3

我认为如果要使用Rails 4.x,您需要将资产预编译到生产环境,或者如果需要,甚至可以同时使用config.assets.compile。

Rails在生产环境下的默认行为是"如果预编译的资源缺失,则不回退到资产管道。"所以不要这样做。 请勿编译。

config.assets.compile = false

如果你使用这个选项,就不需要使用以下内容:
config.serve_static_files = true

因为如果资产未预编译,Rails 将在处理请求之前进行编译。
但如果您在生产前预编译资产,则不需要 config.assets.compile = true,但如果您没有 http_server 来提供预编译的资产,则需要 config.serve_static_files = true 来让 Rails 处理请求。
设置 config.serve_static_assets 已被弃用。
DEPRECATION WARNING: The configuration option `config.serve_static_assets` has been renamed to `config.serve_static_files` to clarify its role (it merely enables serving everything in the `public` folder and is unrelated to the asset pipeline). The `serve_static_assets` alias will be removed in Rails 5.0. Please migrate your configuration files accordingly.

我希望这个答案能够帮助你(读者)理解发生了什么。

0
以下命令在本地运行正常。
rails server -e production

我在运行 "rails s" 时遇到了相同的错误 "ActionController::RoutingError (No route matches [GET] "/assets/application.css""。即使我预编译了源代码,将配置文件 precompile 设置为 true,它仍然无法正确加载。

选项 "-e production" 可以让这些 RoutingError 消失。


2
仅供参考未来的回答(因为这似乎是你的第一次),通常值得解释你正在做什么以及为什么。 - Jon Story

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