【问题标题】:How does one reference compiled assets from the controller in Rails 3.1?在 Rails 3.1 中,如何从控制器中引用已编译的资产?
【发布时间】:2011-09-14 00:14:20
【问题描述】:

我在控制器中使用 PDFkit 构建一系列 PDF,将它们压缩,然后发送给用户。

为了控制输出样式,我告诉 PDFKit 在内容生成期间使用哪些样式表。我需要传递 CSS 文件的文件引用。由于 Rails 现在正在编译和重命名我的样式表,我不确定如何在我的控制器中引用已编译的 CSS 资产。

这是我以前做的:

InvoicesController < ApplicationController
  def download
    kit = PDFKit.new(render_to_string(:show, :layout => false))
    kit.stylesheets << "#{Sass::Plugin.options[:css_location]}/application.css"
    kit.to_file("#{file_date_string}.pdf")
    # snip
  end
end

Sass::Plugin.options[:css_location] 现在返回不正确的位置,更不用说 application.css 不再是文件的有效名称。我应该提一下,我有一个 app/assets/application.css 文件用作我的 SCSS 文件的清单,并且它通过 stylesheet_link_tag() 方法在我的视图中正常工作。

基本上我正在寻找的是一个等效于 assets_path() 的控制器,以便执行以下操作:

kit = PDFKit.new(render_to_string(:show, :layout => false))
kit.stylesheets << asset_path('application.css')
kit.to_file("#{file_date_string}.pdf")

谁能帮忙?

【问题讨论】:

  • 其实这里还有一个问题:你需要使用绝对文件系统路径来引用带有pdfkit的样式表。资产路径虽然返回一个相对的“网络路径”。我现在通过创建一个放在公共/样式表中的 pdf.css 解决了这个问题。不理想,因为它避免了资产管道,但有效并迫使我将 pdf 相关的样式从我的 app.css 中分离出来。
  • 请注明正确答案。这对社区有很大帮助。

标签: ruby-on-rails ruby-on-rails-3.1 asset-pipeline


【解决方案1】:

Rails.application.assets 的文档很少,但它提供了对 Rails 到 Sprockets 的钩子的访问,作为 Sprockets::Environment 对象。 Rails 使用 Sprockets 基本上运行整个资产管道,这就是你应该挂钩的地方:

kit.stylesheets << Rails.application.assets['application.css'].pathname

https://github.com/sstephenson/sprockets 说:

以编程方式访问资产

您可以使用 find_asset 方法(别名为 [])从 Sprockets 环境中检索资产。传递一个逻辑路径,你会得到一个 Sprockets::BundledAsset 实例:

  environment['application.js']
  # => #<Sprockets::BundledAsset ...>

在结果资产上调用to_s 以访问其内容,length 以获取其长度(以字节为单位),mtime 以查询其最后修改时间,pathname 以获取其在文件系统上的完整路径。

【讨论】:

  • 它似乎不适用于需要预编译的资产。它只是加载原始文件(在我的例子中是.scss)。
  • 我正在通过以下两种方式处理 CSS 输出:irb(main):008:0* Rails.version => "3.2.2" irb(main):009:0> Rails。 application.assets["main.css"].to_s == Rails.application.assets["main.css.scss"].to_s => true
  • 虽然文件内容匹配,但由于某种原因,我发现它们在 PDF 中没有正确显示。通过 rack 中间件生成它是可行的,但不是通过显式实例化 PDFKit 对象。我发现我可以让它工作的唯一方法是将编译的样式表放在 /public/ 中,然后将该样式表编码到相关的布局中。例如&lt;link href="&lt;%= "http://#{request.host}:#{request.port}/assets/pdf.css"%&gt;" media="all" rel="stylesheet" type="text/css" /&gt;
【解决方案2】:

view_context.asset_path 'application.css' 应该可以解决问题。

【讨论】:

  • 如果您尝试在 Rails 控制台中签入,ActionController::Base.new.view_context.asset_path "application.css"
【解决方案3】:

Rails.application.assets['application.css'].pathname 总是返回原始资产的原始路径,而不是预编译文件,所以上面的答案对我不起作用。

但是,在捆绑资产上调用 to_s 而不是 pathname 似乎确实可以正确返回预编译资产的主体,因此您可以只使用内联样式而不是使用 kit.stylesheets &lt;&lt;

<style> <%= Rails.application.assets["application.css"].to_s %> </style>

【讨论】:

    【解决方案4】:

    一种解决方案是将 CSS 内联到您的视图中。

    在 HAML 中,这可能如下所示:

    %style
      = Sass.compile(File.read(File.join(Rails.root, 'app', 'assets', 'stylesheets', 'sass', "application.scss")))
    

    或在 ERB 中:

    <style>
      <%= Sass.compile(File.read(File.join(Rails.root, 'app', 'assets', 'stylesheets', 'sass', "application.scss"))) %>
    </style>
    

    【讨论】:

      【解决方案5】:

      获取编译名称的最佳方法是从编译时生成的清单中。

      您可以创建一个控制器方法,在开发中提供原始名称,然后在生产中访问清单以映射正确的名称。

      manifest的默认位置是:

      File.join(Rails.public_path, config.assets.prefix, 'manifest.yml')

      但看起来您可以在 config.assets.digests 中将其作为哈希访问

      config.assets.digests[css_file_name_as_string]

      【讨论】:

        【解决方案6】:

        我认为stylesheet_path("application") 就是您要找的东西

        【讨论】:

        • 很遗憾,没有。 stylesheet_path() 是一个视图助手,我需要它在控制器操作中工作。我尝试将模块包含到控制器中,但它假定存在控制器范围内不存在的assets_path 方法。
        猜你喜欢
        • 1970-01-01
        • 2011-11-17
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-31
        • 2011-12-19
        相关资源
        最近更新 更多