martincarlin87
martincarlin87

Reputation: 11042

How to Use Sprockets Gem Properly with Rails 4

As a bit of pre-text, I am used to Rails 2 but started building a sample app to get used to Rails 4 and I am having a nightmare with Sprockets and the asset pipeline even after reading the official guide and every question I can find on SO.

My css and js are included like so in my main view file:

<head>
   ...
  <%= stylesheet_link_tag "application", media: "all" %>
  <%= stylesheet_link_tag "style-responsive", media: "all" %>

  <%= stylesheet_link_tag params[:controller], :media => "all" if stylesheet_exists?(params[:controller]) %>

  <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
  <!--[if lt IE 9]>
  <%= javascript_include_tag 'html5shiv' %>
  <%= javascript_include_tag 'respond.min' %>
  <![endif]-->
  ...
</head>

....

<%= javascript_include_tag "jquery-1.10.2.min" %>
<%= javascript_include_tag "jquery-ui-1.9.2.custom.min" %>
<%= javascript_include_tag "jquery-migrate-1.2.1.min" %>
<%= javascript_include_tag "bootstrap.min" %>
<%= javascript_include_tag "modernizr.min" %>

<%= javascript_include_tag params[:controller] if javascript_exists?(params[:controller]) %>

stylesheet_exists? and javascript_exists? are helper functions as I only want to include certain files when they are needed as opposed to the rest which are needed on every page.

The first error is:

Asset filtered out and will not be served: add `Rails.application.config.assets.precompile += %w( style-responsive.css )` to `config/initializers/assets.rb` and restart your server

If I then add that to assets.rb and restart, it moves on and the issue is repeated for every stylesheet_link_tag and javascript_include_tag in my view.

I could live with that even if it doesn't seem right but this comes crashing down when the interpreter gets to

<%= javascript_include_tag params[:controller] %>

Would I then need to also include every js file that I create for each controller? This seems wrong that I would have to constantly update the file whenever I create a new asset file.

In my application.css.erb I only have

 *= require_self.

but I do have the old fashioned CSS @import for some stylesheets:

@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic);
@import url('bootstrap.min.css');
@import url('bootstrap-reset.css');
@import url('jquery-ui-1.10.3.css');
@import url('<%= asset_path 'css/font-awesome.min.css' %>');
@import url('custom-ico-fonts.css');

but all of these seem to work fine and don't need to be mentioned in assets.rb.

I have no requires set in application.js.

TLDR I think I am using Sprockets and the Asset Pipeline incorrectly, could someone please point out what it is I'm doing wrong and point me in the right direction?

I read about some similar issues to do with the sprocket-rails gem version 2.2.3 but I have 2.2.4 installed which is meant to have fixed any problems that existed in the previous version.

Rails 4.2.1
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
sprockets (3.0.1, 2.12.3)
sprockets-rails (2.2.4)

Upvotes: 1

Views: 1769

Answers (1)

chrisb
chrisb

Reputation: 36

Sprockets wants to compact everything into a single file and minify it, so typically the pattern is to include all your javascript/stylesheets in the application manifests. There are plenty of good reasons for this pattern.

Since it appears you have removed the = require_tree . lines, this is not happening automatically and thus Rails wants to know about each individual file you plan to include separately via the assets.precompile configuration option. If requiring the entire directory is too aggressive, break your assets into subfolders and be more explicit about what you want to include.

Sprockets is relatively brittle and fighting against it is an uphill battle. So in both cases (JS/CSS), you should include it all and use selectors that are smart enough to scope page-specific styles or JS to that page.

That said, sometimes we cannot avoid having certain assets omitted from global inclusion. If you need to exclude a specific file from your manifest use a stub directive and include it separately with the HTML tag helpers.

Also note that you can have additional manifests (other files that include = require ... directives of their own) ... so long as you add those to the assets.precompile list.

The combination of stub and require directives and additional manifests should give you enough flexibility to organize your assets to your liking and make adding additional assets frictionless.

Upvotes: 2

Related Questions