Rails 应用程序在生产环境中不提供资产

Posted

技术标签:

【中文标题】Rails 应用程序在生产环境中不提供资产【英文标题】:Rails App Not Serving Assets in Production Environment 【发布时间】:2013-07-28 02:47:28 【问题描述】:

我的应用在开发环境中运行时运行良好。在生产中(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。配置文件片段:

应用程序.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

生产.rb

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

宝石文件:

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 的项目中遇到了类似的问题。这里的解决方案都没有解决它。图像和 javascripts 的服务很好,但 css 没有。 css 文件正在编译,显示在 public/assets 中,并显示在清单文件中,但是生产服务器仍然给我这个 css 文件的错误。如果有人有任何想法,我很乐意知道。 【参考方案1】:

在 production.rb 中更改设置:

导轨 3.x

config.serve_static_assets = true

导轨 4.x

config.serve_static_files = true

【讨论】:

我猜它是特定于 rails-3 的。【参考方案2】:

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

RAILS_ENV=production bundle exec rake assets:precompile

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

接下来,您必须告诉 Rails 自己服务资产。服务器软件(例如 nginx 或 Apache)在 Heroku 等环境中为您执行此操作,但在本地您应该让 Rails 执行此操作。在您的 production.rb 中更改此设置:

config.serve_static_assets = true

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

【讨论】:

我正在尝试自己在 ec2 机器上部署此应用程序。在 ec2 上,我安装了 ruby​​、rails,然后做了一个“rails server -e production”。所以我想只是告诉 rails server 命令环境是生产环境不会导致它编译资产?顺便说一句,如果我在 production.rb 中设置 config.assets.compile = true,一切都会重新开始。那么,如果您想自己部署应用程序,最好的方法是什么?如果我用 unicorn 代替 webrick,会有什么不同吗? 告诉 Rails 环境是生产环境并不能真正编译资产。您需要在本地预编译它们。您可能想看看这篇文章,它展示了如何使用 gem 资产同步将您的资产推送到 S3 和 Cloudfront:blog.firmhouse.com/… 如果Server sotware (eg. Nginx or Apache) do it for我。在我的理解中,这意味着在服务器端它被设置为TRUEconfig.serve_static_assets = true),但是为什么我应该在将它推送到服务器之前将它设置回FALSE Papouche,我相信他们的意思是 Nginx 或 Apache 将直接从配置的位置提供资产,而无需使用 Rails。也就是说,Rails 负责处理非资产请求,因此用户无需等待复杂的应用程序框架来提供图像。 Nginx 和 Apache 已经可以很容易地提供静态文件了。 对于 Rails 4,它将是 config.serve_static_filesconfig.serve_static_assets 已弃用,将在 Rails 5 中删除。【参考方案3】:

这听起来像是problem I was having。

我发现 blog 表明这是 Rails 4.0.0 资产管道中的一个错误,并且通过设置莫名其妙地得到缓解...

config.assets.compile = true

...在config/environments/production.rb

除了以某种方式将资产管道投入实际工作之外,该设置还将开启资产的实时编译。这对于生产中的性能通常是一件坏事,但是如果您在部署时仍然手动预编译资产,使用

rake assets:precompile

...实时编译永远不会发生(因为必要的资产已经预编译)。

我希望这会有所帮助:)

【讨论】:

也适用于 4.2。这可能为我节省了几个小时的痛苦 - 谢谢!【参考方案4】:

以下命令在本地对我有效。

rails server -e production

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

选项“-e production”使那些 RoutingError 消失了。

【讨论】:

仅供参考以供将来的答案(因为这似乎是您的第一个答案),通常值得解释一下您在做什么以及为什么。【参考方案5】:

我认为对于 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.

我希望这个答案能帮助你(读者)了解真正发生的事情

【讨论】:

【参考方案6】:

检查这样的文件:

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,因为它可以处理更真实的静态文件服务。

【讨论】:

【参考方案7】:

如前所述,config.serve_static_assets 已弃用并由config.serve_static_files 取代。如果你检查 config/environments/production.rb 的 Rails-4.2,你会发现:

  # 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推送到生产主机。

【讨论】:

【参考方案8】:

在 Rails 5.x 中设置为

config/initializers/assets.rb:

Rails.application.config.public_file_server.enabled = true

https://edgeguides.rubyonrails.org/configuring.html

【讨论】:

以上是关于Rails 应用程序在生产环境中不提供资产的主要内容,如果未能解决你的问题,请参考以下文章

rails 4.1.0.rc1 nginx 和 unicorn 未在生产环境中提供资产

在 Rails 4 生产环境中找不到资产的 404 错误

Rails 5 缓存在本地或生产环境中不起作用

如何在Elastic Beanstalk容器中提供Rails应用程序的webpacked资产?

在 Rails 生产中禁用资产缩小

Rails 4 - 在生产服务器上预编译资产后没有 manifest.json