Rails 3.1 Asset Pipeline不预编译来自不同目录的文件

时间:2012-02-13 13:03:10

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

我目前有一个Rails 3.1应用程序,可以为多个不同的客户托管多个站点。 每个站点都由一个模型表示,该模型知道域名和资产存储路径,以及其他一些信息。

我一直使用app/sites/domain-name作为存储特定于某个站点的资产,视图和区域设置的位置,并且正在运行自定义中间件和控制器操作来修改Sprockets的加载路径,设置视图路径等。

中间件(使用config.middleware.use "Configurator"中的application.rb加载):

class Configurator
  def initialize(app)
    @app = app
  end

  def call(env)
    @env = env
    clear_existing_paths
    prepend_local_assets
    @app.call(env)
  end

  def current_site
    # find site using @env
  end

  def current_site_path
    Rails.root.join('app', 'sites', current_site.path)
  end

  def clear_existing_paths
    paths = Rails.application.assets.paths
    Rails.application.assets.clear_paths
    paths.each do |path|
      next if path.include?("app/sites/")
      Rails.application.assets.append_path path
    end
  end

  def prepend_local_assets
    path = current_site_path.join('assets')
    return unless Dir.exists?(path)

    ['images', 'javascripts', 'misc', 'stylesheets'].each do |subdir|
      asset_dir = path.join(subdir).to_s
      next unless Dir.exists?(asset_dir)
      next if     Rails.application.assets.paths.include? asset_dir

      Rails.application.assets.prepend_path asset_dir
    end
  end
end

来自application.rb的资产位:

module MyApp
  class Application < Rails::Application
    ...
    config.middleware.use "Configurator"

    config.assets.enabled = true 
    config.assets.version = '1.0'
  end
end

environments/production.rb

MyApp::Application.configure do
  config.serve_static_assets = false
  config.assets.compress = true
  config.assets.compile = true
  config.assets.digest = true
  # Defaults to Rails.root.join("public/assets")
  # config.assets.manifest = YOUR_PATH
end

问题在于,虽然此设置有效,但它阻止我预编译未与整个应用共享的资产,从而使它们从外观上反复生成。

有什么方法可以让预编译器找到位于此处的资产,并创建这些资产的版本?每个站点都有一个site.css.scss和一个site.js.coffee文件,可能需要site-dir中的其他资产。如果我能将它预编译到public/assets/domain-name/site.(js|css)会很好,所以当我需要进一步优化时,我可以轻松地为资产设置一个单独的子域

最终解决方案(2012-02-22)

在实施了Brian的建议后,我最终得到了

主要样式表/ javascript存储在app/sites/<sitename>/assets/<shortname>/site.css|js中,其中sitename是此网站的域名,shortname是域名的主要部分,没有子域名或com | org |净|。ccTLD的

修改了所有视图和样式表,以便将shortname添加到资产路径中。

config/application.rb

{ "sitename" => "shortname", ... }.each_pair do |domain, short|
  %w{stylesheets javascripts}.each do |dir|
    config.assets.paths << Rails.root.join("app/sites/#{domain}/assets/#{dir}").to_s
  end # Had to specify each dir to make it work
  config.assets.precompile += ["#{short}/site.css", "#{short}/site.js"]
end

运行rake assets:precompile时,会创建public/assets/shortname,其中包含该网站的所有资产,public/assets也拥有所有共享资源。适合我的需求。

由于所有内容都以public/assets结尾,我可以放弃Configurator - 中间件,因为默认配置能够找到所有资产

2 个答案:

答案 0 :(得分:7)

我认为问题是,通过将每个站点添加为路径,sprockets只找到第一个site.scss

我用罗盘试过这个,但对于普通链轮来说应该是一样的。 我没有尝试过你的配置器方法,但看起来很容易使我的安排适应它。

您可以将app / sites / *更改为更标准的文件安排吗?

./app/assets/javascripts/application.js
./app/assets/stylesheets/screen.css.scss
./app/assets/stylesheets/othersite/screen.css.scss

更改您的config / application.rb,并添加您的每个网站。 这将在您的每台主机上预生成所有样式:

config.assets.precompile += ['screen.css', 'othersite/screen.css']

在您的视图/布局/应用程序中,您需要配置网站名称的路径:

= stylesheet_link_tag '[your sitename here]/screen'

我耙资产后:清理和预编译,我在公开场合看到了这一点:

./assets/othersite/screen.css
./assets/othersite/screen.css.gz
./assets/screen.css
./assets/screen.css.gz

答案 1 :(得分:1)

看起来Rails设法找到资产,至少在我将config/environments/production.rb更改为包含

config.assets.precompile += %w( site.js site.css )

config/application.rb包括

config.assets.paths << Rails.root.join("app/sites/sitename/assets/stylesheets").to_s

这为我提供了一个预编译版本,但仅适用于第一个拥有site.css的网站。我想将它们重命名为sitename.css,或者添加一个额外的子目录sitename/site.css也可以。