Ruby on rails 3.1 部署到子URI时,Rails 3.1中的预编译资产已损坏
我正在更新Rails 3应用程序以使用Rails 3.1,作为这一过程的一部分,我正在利用新的资产管道。到目前为止,除了一个我无法解决的恼人问题外,我的一切都正常工作 该应用程序及其所有资产在开发过程中运行良好,但在生产过程中,它使用Passenger(Ruby on rails 3.1 部署到子URI时,Rails 3.1中的预编译资产已损坏,ruby-on-rails-3.1,asset-pipeline,passenger,assets,sprockets,Ruby On Rails 3.1,Asset Pipeline,Passenger,Assets,Sprockets,我正在更新Rails 3应用程序以使用Rails 3.1,作为这一过程的一部分,我正在利用新的资产管道。到目前为止,除了一个我无法解决的恼人问题外,我的一切都正常工作 该应用程序及其所有资产在开发过程中运行良好,但在生产过程中,它使用Passenger(http://the-host/sub-uri/)。这方面的问题是,资产是在部署期间预编译的,我的一个CSS(嗯,它是.CSS.scss文件)文件正在使用sass railsgem中的图像url帮助程序。由于在预编译过程中,路径硬编码到预编译的C
http://the-host/sub-uri/
)。这方面的问题是,资产是在部署期间预编译的,我的一个CSS(嗯,它是.CSS.scss
文件)文件正在使用sass rails
gem中的图像url
帮助程序。由于在预编译过程中,路径硬编码到预编译的CSS文件中,因此不考虑子uri:
在我的.css.scss
文件中:
body { background-image: image-url("bg.png"); }
body { background-image: url(/assets/bg.png); }
编译的应用程序-.css
文件中的结果:
body { background-image: image-url("bg.png"); }
body { background-image: url(/assets/bg.png); }
如何使其正常工作:
body { background-image: url(/sub-uri/assets/bg.png); }
这是不是要求太多了?如果是这样,我将不得不切换回旧的非资产管道方式,只从public
提供我的图像和CSS。然而,这似乎是应该考虑和解决的事情。。。?我是否错过了解决方案
编辑1:我应该注意,使用的结果与预期的相同
编辑2:回应Benoit Garret的评论 不,问题与
config.assets.prefix
无关。我尝试将其设置为/sub-uri/assets
,而不是默认设置为/assets
),但结果是这样做是错误的-似乎此设置已经与Rails应用程序的根相关,而不是与服务器相关。删除它(并因此返回默认设置)修复了所有导致的奇怪问题(有很多,所有的资产都以/sub-uri/sub-uri/assets
-这一切都很奇怪)。唯一的问题是,图像url
助手和朋友在预编译时没有获取子URI。不用说,这是合乎逻辑的,因为当它被预编译时,它不可能知道当它在Passenger下运行时,它将以这种方式配置。我的问题是如何告知它这一点,从而在预编译结果中得到正确的路径。如果确实可以做到的话
我目前的解决方法是像这样引用CSS中的iamge:
url(../images/bg.png)
并将其放置在非流水线public/images
位置。这并不理想,因为它不能从指纹识别和管道提供的一切中获益。最后,我想出了一些解决方法
1) 从它看来,这可能会在sass rails中得到修复。我已经按照上面链接中建议的补丁程序对helpers.rb进行了修改。我只需在deploy.rb
中的资产预编译行中设置所需的环境变量
我在一个文件config/initializers/gem_patches.rb
中完成所有的猴子补丁。在此文件中,我将此方法修补为:
module Sass
module Rails
module Helpers
protected
def public_path(asset, kind)
path = options[:custom][:resolver].public_path(asset, kind.pluralize)
path = ENV['PRODUCTION_URI'] + path if ENV['PRODUCTION_URI']
path
end
end
end
end
2) 或者,如果您可以在CSS中嵌入图像,则将样式表更改为具有.erb扩展名,并将
图像url(“bg.png”)
替换为url()
,这将不需要更改sass rails<代码>资产数据uri不作为纯Sass函数存在,因此您必须使用Rails助手资产数据uri
经过一番挖掘,我发现了这个问题。问题出现在Rails中,特别是链轮::Helpers::RailsHelper::AssetPath#compute_public_path。链轮::Helpers::RailsHelper::AssetPath继承自ActionView::AssetPath并重写许多方法。当通过Sass::Rails::Resolver调用compute_public_path时,公共_path方法是Sass Rails,Rails链轮帮助器将承担解析资源的任务。链轮::Helpers::RailsHelper::AssetPath#compute#public(计算公共)路径服从于super,即ActionView::AssetPath#compute#public(计算公共)路径。在这个方法中有一个条件has_request?在重写\u相对\u url\u根时,如下所示:
def compute_public_path(source, dir, ext = nil, include_host = true, protocol = nil)
...
source = rewrite_relative_url_root(source, relative_url_root) if has_request?
...
end
def relative_url_root
config = controller.config if controller.respond_to?(:config)
config ||= config.action_controller if config.action_controller.present?
config ||= config
config.relative_url_root
end
如果您查看rewrite_relative_url_root的内部结构,它依赖于要出现的请求以及从控制器变量派生该请求以解析相对url root的能力。问题是,当链轮为sass解析这些资产时,它没有控制器,因此没有请求
上面的解决方案在我的开发模式下不起作用。以下是我目前正在使用的解决方案:
module Sass
module Rails
module Helpers
protected
def public_path(asset, kind)
resolver = options[:custom][:resolver]
asset_paths = resolver.context.asset_paths
path = resolver.public_path(asset, kind.pluralize)
if !asset_paths.send(:has_request?) && ENV['RAILS_RELATIVE_URL_ROOT']
path = ENV['RAILS_RELATIVE_URL_ROOT'] + path
end
path
end
end
end
end
在最新的Rails 3.1.3中,您需要立即对另一个模块进行猴子补丁,以使其正常工作 这就是我所做的
module Sprockets
module Helpers
module RailsHelper
def asset_path(source, options = {})
source = source.logical_path if source.respond_to?(:logical_path)
path = asset_paths.compute_public_path(source, asset_prefix, options.merge(:body => true))
path = options[:body] ? "#{path}?body=1" : path
if !asset_paths.send(:has_request?)
path = ENV['RAILS_RELATIVE_URL_ROOT'] + path if ENV['RAILS_RELATIVE_URL_ROOT']
end
path
end
end
end
end
在我的deploy.rb中,我有:
desc "precompile the assets"
namespace :assets do
task :precompile_assets do
run "cd #{release_path} && rm -rf public/assets/* && RAILS_ENV=production bundle exec rake assets:precompile RAILS_RELATIVE_URL_ROOT='/my_sub_uri'"
end
end
before "deploy:symlink", "assets:precompile_assets"
我正在使用Rails 3.1.3并成功地部署到子URI。 我什么也没补 对该设置的关键问题进行了更好的讨论。正如您所看到的,该解决方案应用于Rails 3.2,从未向后移植到3.1.4 但是,我使用Rails 3.1.3找到了一个适合我的设置的解决方案 试试这个:(我不是专家,只是想为解决一个困扰了我好几个小时的问题做出贡献…) environment.rb:
#at top:
ENV['RAILS_RELATIVE_URL_ROOT'] = '/rais'
production.rb:
config.assets.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] ? ENV['RAILS_RELATIVE_URL_ROOT'] + '/assets' : '/assets'
routes.rb:
Rais::Application.routes.draw do
scope ENV['RAILS_RELATIVE_URL_ROOT'] || '/' do #see config/environment.rb
<<resources here>>
end
end
然后,使用控制台进行测试:
RAILS_ENV=production rails console
结果:
foo = ActionView::Base.new
foo.stylesheet_link_tag 'application'
=> "<link href=\"/rais/assets/layout.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"/rais/assets/application.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
foo.image_tag('arrow-up.png')
=> "<img alt=\"Arrow-up\" src=\"/rais/assets/arrow-up-ca314ad9b991768ad2b9dcbeeb8760de.png\" />"
foo=ActionView::Base.new
foo.stylesheet\u link\u标记“application”
=>“\n”
foo.image_标记('arrow-up.png'))
=> ""
您尝试过这个吗?应用程序本身部署得很好(它确实使用RailsBaseURI方法,因为这是乘客文档推荐的方法)。在运行中的应用程序中链接到的所有资产,如使用image\u标记的图像等,都是正常的。唯一的问题是CSS中引用的图像-在预编译资产时,它不知道子URI。就是为了这个