3

例如,是否可以在 Sinatra 中有一个 css.erb 文件来提供来自 AWS 的图像。我正在从 AWS 中提取我的静态资产,并且可以在我的视图中提取图像,例如

<%= image_tag( aws_asset "/assets/img/banner2.jpg") %>

aws_asset 是设置 AWS url 的助手

helpers do
 def aws_asset( path )
 File.join settings.asset_host, path
 end
end

configure :development do 
 set :asset_host, "https://s3-eu-west-1.amazonaws.com/#{ENV['FOG_DIRECTORY']}" 
end

所以问题是我如何从我的 css 文件中获取背景图像以从 AWS 中提取该图像

编辑

当前设置

我的应用程序.rb

get "/assets/css/style.css" do
erb :style 
end

布局.erb

<%= stylesheet_link_tag  "/assets/css/style.css"  %>

样式.css

body {
background: url('<%= aws_asset "/assets/img/banner1.jpg" %>');

}

谢谢

4

1 回答 1

3

由于您已经为此使用 ERB:

body
{
  background-image:url('banner2.jpg');
}

会成为:

body
{
  background-image:url('<%= aws_asset "/assets/img/banner2.jpg" %>');
}

这就是简单的答案。但是,由于您可能要从 AWS 提供相当多的文件,然后在您需要的所有不同地方使用帮助程序可能会变得令人厌烦,而且也很困难 - 也许您将来会想要预编译 CSS 等等。这是什么时候使用 Rack 中间件隐藏一些实现是个好主意。

module MySinatraApp

  # A remote file called banner2.jpg would have the relative path
  # in the app of "/images/extra/banner2.jpg"
  # and on being requested, this middleware/app would check if
  # the remote file is in the list you've given
  # if it is, a 307 redirect is issued.
  # If it isn't, then a 404. Use with Rack::Cascade to pass on
  # to another app that may serve a local version of the file.
  # @example
  #   use RemoteImageServer, 
  #       :asset_host => "//s3-eu-west-1.amazonaws.com"
  #       :files      => ["banner2.jpg", "blah.gif"]
  class RemoteImageServer
    DEFAULT_OPTIONS = {
      subdir:        "images/extra",
      cascade:       false # until I work it out more, see note at bottom
    }

    def initialize(app,options={})
      app, options = app, DEFAULT_OPTIONS.merge(options)
      @asset_host = options[:asset_host]
      files = options[:files]
      @subdir = options[:subdir]
      @http_path_files = files.map{|file| File.join @subdir, file }
    end

    def call( env )
      dup._call( env ) # for thread safety
    end

    def _call( env )
      request = Rack::Request.new env
      if request.path_info.start_with? @subdir
        response = Rack::Response.new env
        if @http_path_files.include? request.path_info
          response.redirect File.join(@asset_host,request.path_info), 307
          response.finish
        else
          if @options[:cascade]
            response.status = 404
            response.finish
          end
        end
      else
        @app.call env
      end
    end
  end

  class MainApp < Sinatra::Base do
    # other stuff here…
  end

end

您可以在 Sinatra Application或 rackup 文件中使用它。我更喜欢后者并使用Rack::Cascade

运行 Rack::Cascade.new([MySinatraApp::RemoteImageServer, MySinatraApp::MainApp])(我不确定在使用级联时如何最好地传递选项,我可能需要更多地考虑这一点)。

  use RemoteImageServer, 
    :asset_host => "//s3-eu-west-1.amazonaws.com"
    :files      => ["banner2.jpg", "blah.gif"]
  run MySinatraApp::MainApp

这样,远程主机就“隐藏”在了相对 url 后面,您可以用本地文件替换远程文件,或者轻松更改远程提供程序。最后的 Sinatra 应用程序仍将提供其公用文件夹中的任何本地文件。不过,这段代码完全未经测试!可能有一个 Rack 中间件已经这样做了(Rack Static Fallback可能很接近)。


编辑:通过 ERB 提供 CSS。

主要有2种方式:

  • 预编译 CSS 并通过public_folder.
  • get路线上服务。

预编译 CSS

可能有一个 gem 或其他东西可以做到这一点(可能是一个Guard助手或其他东西),但这将在控制台中工作:

require 'erb'
require 'tilt'
template = Tilt.new( "path/to/erb/file" )
File.open "app/public/stylesheets/main.css", "w" do |f|
  f.write template.render
end

由于编译后的 CSS 文件将驻留在 Sinatra 的公共目录中,因此它将作为静态文件提供。由于您在aws_asset文件中获得了来自 Sinatra 的帮助程序,因此您需要稍微更改它,或者在运行它之前在控制台中重新定义帮助程序,或者对路径进行硬编码,或者将其传递给变量

从 Sinatra 获取路线上提供服务

get "/css/main.css" do
  erb :main # it will server main.erb from the views directory
            # and it will have access to helpers.
end

由于它是一个不会经常更改的文件,因此您最好添加缓存控制标头

于 2013-03-20T22:31:26.770 回答