Search code examples
ruby-on-rails-3.2sasscompass-sasssprocketszurb-foundation

Sass @import directive when used in Rails engine can't find assets in plugins


I was building a Rails engine that uses zurb-foundation's stylesheets, and kep hitting the same Sass::Syntax error. This seemed strange because I had followed the same procedure in a Rails application and it was worked on the first try. So I decided to zero in on the isse by starting two new rails projects--one application and one engine--and configure them to use foundation with a minimal amount of setup.

I started with 2 clean Rails 3.2.9 projects--one application and one engine --full and configured them both manually for foundations by adding foundation_and_overrides.scss and require-ing it in the CSS manifest.

I then creating a bare-bones controller so I'd have a page to load. For the application, loading that page and looking at the page source, I can see that foundation CSS was compiled correctly and loaded.

When I tried the same thing for the engine, I got this error:

Sass::SyntaxError in Main#index

Showing /<PLUGIN_PATH>/test/dummy/app/views/layouts/application.html.erb where line #5 raised:

File to import not found or unreadable: foundation/common/ratios.
Load path: /<PLUGIN_PATH>/test/dummy
  (in /<PLUGIN_PATH>/app/assets/stylesheets/example_plugin/foundation_and_overrides.scss)

(Note that the dummy app's CSS manifest is require-ing the plugin's CSS manifest, which is require-ing foundation_and_overrides.scss. The wiring is clearly not the issue because the error is raised from foundation_and_overrides.scss)

I tried this with several builds of Ruby-1.9.3 (p125, 194, p327, I think) with the same results.

It still didn't work when I added this line to test/dummy/config/application.rb:

config.assets.paths << "#{Foundation::Engine.root}/scss"

even though foundation/common/_ratios.scss exists at that path.

The issue may be with Sass, Sprockets, Compass, Foundation or Rails, so I don't know where to go from here.

I reported it as an issue with Foundation, but I'm not so convinced of that.

Has anyone seen this before?


Solution

  • I found the answer in this Stackoverflow question

    The issue is that a Rails engine's dummy app and a regular Rails app have slightly different config/application.rb files.

    In a Rails app, you'll see this code towards the top:

    if defined?(Bundler)
      # If you precompile assets before deploying to production, use this line
      Bundler.require(*Rails.groups(:assets => %w(development test)))
      # If you want your assets lazily compiled in production, use this line
      # Bundler.require(:default, :assets, Rails.env)
    end
    

    But in an engine dummy app, instead you see:

    Bundler.require
    require "<PLUGIN_NAME>"
    

    In the Rails app, the first Bundler.require include all groups in the Gemfile but excludes :assets unless Rails.env is :development or :test The second Bundler.require includes :default--that is, anything in your Gemfile that's not in a group--as well as :assets and either :production, :development or :test

    In a dummy app, none of this is necessary because 1) it's not meant to be used in production, and 2) test and development typically have similar dependency requirements. Since the :assets group is just a convenient way to apply dependencies to :test and :development but not to :production, in a dummy app it's the same as :default. So in a dummy app, nothing but :default is needed. Since Bundler.require is (Warning: Spoiler ahead) the same as Bundler.require(:default), the dummy app just uses Bundler.require. This means that anything in your Gemfile that's in a group will be ignored.

    So the problem I had was that I was copy-and-pasting from a Rails app Gemfile into a Rails dummy app Gemfile, including group :assets do.... I removed the group line and everything worked!

    ADDED later in the day on 11/29:

    To clarify, the error I was seeing is because sass-rails wasn't included (since it was in the :assets group in my Gemfile), so instead of my assets being parsed as Sass, they were parsed as CSS. Since @import means something different to CSS than to Sass, whatever was parsing the CSS file was using a different implementation of @import and couldn't find the file.