简体   繁体   中英

Rails 3.1 Asset Pipeline not precompiling files from a different directory

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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM