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

发布于 2025-01-05 05:05:27 字数 3066 浏览 1 评论 0原文

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

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

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

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

以及 环境/生产.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 文件,可能需要站点目录中的其他资源。如果我可以将其预编译为 public/assets/domain-name/site.(js|css) 那就太好了,这样我就可以在需要时轻松地为资产设置一个单独的子域进一步优化

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

在实现了 Brian 的建议后,我最终将

主样式表/javascript 存储在app/sites//assets//site.css|js,其中 sitename 是此网站的域,shortname 是域的主要部分,没有子域或 com|org|net|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 中间件,因为默认配置能够找到所有资产

I currently have a Rails 3.1 app that hosts multiple sites for several different customers.
Each site is represented by a model that knows the domain name and path to where the assets are stored, along with some other info.

I've been using app/sites/domain-name as a location for storing assets, views and locales that are specific to a given site, and are running a custom middleware and controller actions for modifying the load path for Sprockets, setting up the view paths and so on.

middleware (loaded using config.middleware.use "Configurator" in 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

Asset bits from application.rb:

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

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

And 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

The problem is that while this setup works, it prevents me from precompiling the assets that is not shared with the entire app, making them be generated over and over again, from the looks of it.

Is there any way I could tell the precompiler to find the assets located here, and create a version of those as well? Each site has a site.css.scss and a site.js.coffee file that might require other assets inside the site-dir. Would be nice if I could get it precompiled to public/assets/domain-name/site.(js|css), so I could easily set up a separate subdomain for assets down the line when I need to optimize further

Final solution (2012-02-22)

After implementing what was suggested by Brian, I have ended up with

Main stylesheet/javascript stored in app/sites/<sitename>/assets/<shortname>/site.css|js, where sitename is the domain for this site, and shortname is the main part of the domain, with no subdomain or com|org|net|ccTLD.

Modified all views and stylesheets to prepend shortname to my asset paths.

In 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

When running rake assets:precompile this creates public/assets/shortname filled with all the assets for that site, and public/assets have all the shared assets as well. Works great for my needs.

And since everything ended up in public/assets, I was able to drop the Configurator-middleware, since the default configuration was able to find all the assets

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自在安然 2025-01-12 05:05:27

我认为问题是,通过将每个站点添加为路径,链轮只能找到

我使用指南针尝试过的第一个 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

I think the problem is, by adding each site as a path, sprockets only finds the first site.scss

I've tried this using compass, but it should be the same for plain sprockets.
I haven't tried your configurator approach, but it looks straightforward to adapt my arrangement to it.

Can you change your app/sites/* to the more standard file arrangement?

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

Change your config/application.rb, and add each of your sites.
This will pregenerate all styles, on each of your hosts:

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

In your view/layouts/application, you'll need to configure the path to sitename:

= stylesheet_link_tag '[your sitename here]/screen'

After I rake assets:clean and precompile, I see this in public:

./assets/othersite/screen.css
./assets/othersite/screen.css.gz
./assets/screen.css
./assets/screen.css.gz
中性美 2025-01-12 05:05:27

设法找到资产

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

看起来 Rails 至少在我更改 config/environments/Production.rb 以包含和 config/application.rb 以包含时

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

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

Looks like Rails manages to find the assets at least when I changed config/environments/production.rb to include

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

and config/application.rb to include

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

This gives me a precompiled version, but only for the first site to have a site.css. I guess renaming them to sitename.css, or add a extra subdirectory sitename/site.css might work as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文