Rails 6 stylesheets and sass aren't loading - ruby-on-rails

I've got a new spree rails 6 application and I can't get any of the sass files to compile. Here's my assets/stylesheets file:
stylesheets
app
_file.scss
_another_file.scss
mixins
_mix-media-queries.scss
_mix-general.scss
modules
_modules_file.scss
application.css
style.scss
application.css:
*= require_tree .
*= require_self
*= require ./style
style.scss:
#import "mixins/_mix-media-queries";
etc...
But when I load the page it give me this error:
Error: Undefined variable: "$color-dark-red". Which is an var in the mixins file.
_head.html.erb:
<title><%= title %></title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<%== meta_image_data_tag %>
<%== meta_data_tags %>
<%= canonical_tag(current_store.url) %>
<%= favicon_link_tag 'favicon.ico' %>
<%= stylesheet_link_tag 'spree/frontend/all', media: 'screen', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_link_tag "application", media: "all" %>
<%= csrf_meta_tags %>
<%= render 'spree/shared/paths' %>
<%= javascript_include_tag 'spree/frontend/all', defer: true, 'data-turbolinks-track': 'reload' %>
<%= yield :head %>
This is so frustrating as I cannot get the stupid styles to load! I'm new to rails 6, is this a new rails 6 thing with the asset pipeline?

Sprockets directives do not work well at all with SASS.
When you require SASS files with sprockets it will send the files through the SASS compiler one by one and then concatenate the results together. Of course this blows up as soon as one of your SASS files references a variable, include or function that is declared in any other file.
You need to change the extension of your application.css to .scss and only use SASS #import directives that tells the SASS compiler to pull in the other file.
is this a new rails 6 thing with the asset pipeline?
No. This applies to previous versions of Rails and both SASSC and the old Ruby Sass Compiler.
See:
https://github.com/rails/sass-rails#important-note

Related

How to add stylesheets in ruby on rails

I am referencing stylesheets in my index.html.erb file as below
<%= stylesheet_link_tag "/stylesheets/CSS/External/bootstrap.min.css" %>
I have my folder structure as
apps\assests\stylesheets\CSS\Internal
and
apps\assests\stylesheets\CSS\External
But in page, it is rendering as below
<link rel="stylesheet" media="screen" href="/stylesheets/CSS/External/bootstrap.min.css">
Also, I see that my files are rendering twice as attached image
and I get the following errors
First of all, you don't need this line in index.html.erb
<%= stylesheet_link_tag "/stylesheets/CSS/External/bootstrap.min.css" %>
because it's included globally into layouts/application.html.erb something like this
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
For JS
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
This will mapping automatically from assets folder.
If your folder structure like this stylesheets/CSS/External then opens your application.css and add like this
*= require CSS/External/bootstrap.min
after *= require_tree .
You can use Bootstrap Ruby Gem for bootstrap styling, it's simple & easy to implementation based on there doc
Update
For example, the directories are assets/stylesheets/css/external and the css file are inside this directory like
assets/stylesheets/css/external/
...............................bootstrap.css
...............................other.css
and your assets/stylesheets/application.css
/*
*= require_tree .
*= require css/external/bootstrap
*= require css/external/other
*= require_self
*/

Rails assets compile application.js file on Heroku

I have couple of vendor js files and I put them in the application.html.erb of bottom of body tag as;
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<meta charset="utf-8" />
<title><%= full_title(yield(:title)) %></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta content="" name="description" />
<meta content="" name="author" />
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<meta name="viewport" content="initial-scale = 1.0,maximum-scale = 1.0" />
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<% if (controller.controller_name == "main") %>
<body class="fixed-header no-header">
...
<%= javascript_include_tag 'pace/pace.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'modernizr.custom', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'jquery-ui/jquery-ui.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'boostrapv3/js/bootstrap.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'jquery/jquery-easy', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'jquery-unveil/jquery.unveil.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'jquery-bez/jquery.bez.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'jquery-ios-list/jquery.ioslist.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'jquery-actual/jquery.actual.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'jquery-scrollbar/jquery.scrollbar.min', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'bootstrap-select2/select2.min', 'data-turbolinks-track' => true %>
...
</body>
</html>
Then I declared them for Rails to be able compile (config/initializers/assets.rb)
Rails.application.config.assets.precompile += %w( pace/pace.min.js modernizr.custom.js jquery-ui/jquery-ui.min.js boostrapv3/js/bootstrap.min.js jquery/jquery-easy.js jquery-unveil/jquery.unveil.min.js jquery-bez/jquery.bez.min.js jquery-ios-list/jquery.ioslist.min.js jquery-actual/jquery.actual.min.js jquery-scrollbar/jquery.scrollbar.min.js bootstrap-select2/select2.min.js switchery/js/switchery.min.js ...)
Then I have signup to heroku and created an app then I typed;
1. bundle exec rake assets:precompile RAILS_ENV=production
2. git add .
3. git commit -m "smth"
4. git push heroku master
app works fine but the problem is in the network tab. I have application.js file but I have all the vendor js files individually. Should not be rails compiling them to 1 file ?
EDIT:
I really could not figure it out how should I include vendor js files to rails app. As most of the js files work after the dom loads, I would like them to load at the end of body tag.
I removed the app and push again to heroku. I changed nothing. Now the js files works but weirdly it seems not loading.
I did not require any vendor file in application.js file.
EDIT 2
I really appreciate your answer and trying to understand one more thing.
Lets say I have a model called main.rb so I have main folder and home.html.erb file. Rails creates main.coffee ( I changed it to main.js.coffeee). So if I put all the relevant js codes into this file (main.js.coffee), whenever home.html.erb is called this js code will automatically called after page loads, is that how it works?. If so, I will organize page specific js codes like this. thank you
You are loading them all directly from the page as well as from the concatenated precompiled file so what you are seeing is the concatenated file being loaded and then the libraries are getting reloaded a second time from the separate js include tags in your application.html.erb file! What you need to do is require them in your app/assets/javascripts/application.js file so that they are loaded once.
For example in your app/assets/js/application.js file should be:
//= require pace/pace.min
//= require bootstrap-select2/select2.min
Do this for all the js files and then make sure if any js files aren't working properly to account for turbolinks by calling the page:change event as described here:
Rails 4: how to use $(document).ready() with turbo-links
EDIT: Loading js libraries in the Head tag is noramlly fine because they're all usually wrapped in a $(document).ready call so there is no need to force them into the end of the page like you would for php and other platforms. The Rails Way to handle this is to require them as stated in your application.js and then run bundle exec rake assets:precompile RAILS_ENV=production . Then do another git add and commit and then push to heroku!
Now, to do what you want and keep js at the bottom of specific pages you have to realize your application.html.erb gets called for every page request so you're essentially loading this script into every page like your application.js asset file is designed for. If you want to only call js on specific pages and at the bottom you can do the following:
In your application.html.erb file at the very bottom before the closing body tag you can put:
<%= yield :javascript %>
Then on all view pages where you have some script or library you'd like to include you can put at the very bottom of that view:
<%= content_for :javascript do %>
<script src="jquery-1.12.2.min.js"></script>
<script type='text/javascript'>
all your custom js here....
</script>
<% end %>
This will yield the block of js to the :javascript in your application.html.erb at the bottom as desired.
Edit 3:
You'll notice the standard Rails application.js file has a "require_tree" directive. This basically loads all js so scripts that you have in your main.js folder will fire on anything referencing them in any other part of your application. To avoid this you can do what I do and remove these directives and call things individually. This is a bit more advanced but I'll walk you through it since it's hard to put it all together on docs scattered around the internet. This is how to load page specific assets and the ideal way to handle assets in Rails.
In your application.js file remove the require_tree and only //=require files you want application wide whether it's libraries in your vendor js folder or personal scripts. Once that is done, you'll need to change your application.html.erb file as follows:
In the head tag you can keep the "javascript_include_tag application" call since that will do what you want and pull all app. wide js files. Then at the bottom of this file above the closing body tag put:
<%= javascript_include_tag params[:controller] if ::Rails.application.assets.find_asset("#{params[:controller]}.js") %>
This will then call only the js file with the matching controller name such as 'main.js' in your example. I also then under this line use a yield to javascript code that may be on other views:
<%= yield :javascript %>
Then on pages with page specific js I put it at the very bottom of its respective view and don't add it to my assets/js folder at all:
<%= content_for :javascript do %>
<script type='text/javascript'>
code here
</script>
<% end %>
Now you're almost done. Because you will be loading files by controller you need to add them to your Rails precompile list! So for example, your 'main.js' file, even if it is autocreated when generating a controller, must be added to this precompiled array with all other controller js files. To do this open up your config/initializers/assets.rb file and uncomment the following line and add all js files named after controllers:
Rails.application.config.assets.precompile += %w ( main.js )
Now restart your server and you are done! I do this for css files as well!
Note: If you have js libraries that are only used in one page you can do the //= require statement in those controller related js files. //= require is not limited to the application.js file!

Ruby on rails bootstrap css js working but not found

I have a rails application which I added the bootstrap gem
first I added this two gems
gem 'bootstrap'
gem 'sprockets-rails', :require => 'sprockets/railtie'
which installed this packages
Using bootstrap 4.0.0.alpha3
Using sprockets 3.6.0
After I modified application.scss to
// Custom bootstrap variables must be set or import before bootstrap itself.
#import "bootstrap";
Then I left application.js like this
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require tether
//= require bootstrap-sprockets
//= require_tree .
//= require_self
Lastly my application.html.erb is this
<!DOCTYPE html>
<html>
<head>
<title>Squirm</title>
<%= stylesheet_link_tag "bootstrap" %>
<%= javascript_include_tag "bootstrap" %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= render 'partials/navbar' %>
<div class="container">
<%= yield %>
</div>
</body>
</html>
Bootstrap seems to we working, but in the Google Chrome console seems not to be found
You're loading Bootstrap before you've loaded jQuery. Many of Bootstrap's components require javascript (carousel, tabs, etc.), however, most of Bootstrap will work without, which is why the Bootstrap CSS is showing on your page.
Loading Bootstrap after jQuery will fix the issue:
<!DOCTYPE html>
<html>
<head>
<title>Squirm</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= stylesheet_link_tag "bootstrap" %>
<%= javascript_include_tag "bootstrap" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= render 'partials/navbar' %>
<div class="container">
<%= yield %>
</div>
</body>
</html>
Also, not 100% sure based on your code, but you may be loading bootstrap twice. It seems this line: //= require bootstrap-sprockets is already loading Bootstrap.
you need to add jquery as well normally jquery come bundled in rails app, but maybe due to some reasons its not thr in your app
add
jquery from
https://cdnjs.com/libraries/jquery/
and let us knwo if this change works.

Formtastic Install breaking Bootstrap CSS stylesheet

I'm using Rails 4. I'm installing formtastic and in the process following the Readme to make changes to the CSS. This is breaking my CSS - my pages are showing but without any formatting at all.
My Application.css file (I removed *= require_tree . per instructions on readme):
*= require_self
# app/assets/stylesheets/application.css
*= require formtastic
*= require my_formtastic_changes
# app/assets/stylesheets/ie6.css
*= require formtastic_ie6
# app/assets/stylesheets/ie7.css
*= require formtastic_ie7
In application.html.erb note I commented out the previous stylesheet and added in a new link:
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%# stylesheet_link_tag "application",
"data-turbolinks-track" => true %>
<%= stylesheet_link_tag "application", "formtastic", "my_formtastic_changes" %>
<!--[if IE 6]><%= stylesheet_link_tag 'ie6' %><![endif]-->
<!--[if IE 7]><%= stylesheet_link_tag 'ie7' %><![endif]-->
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %>
</div>
</body>
</html>
I also added the stylesheet my_formtastic_changes.css.scss, an empty file. I experimented with adding/removing the formtastic and my_formtastic_changes references and using single and double quotes with the stylesheet references - no luck there.
I left the require_tree . line out but had to add in
*= custom
So it loaded the custom stylesheet, including the bootstrap CSS.

Configuring Rails Asset Pipeline in dev and production

I am still not quite sure about the best practice of using rails asset pipeline. In a rails skeleton project, the application.html.erb contains code as:
<head>
<title>My title</title>
<%= stylesheet_link_tag "scaffolds" %>
<%= stylesheet_link_tag "depot", media: "all" %>
<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
Now in development, all js and css would be served properly. But in production, after precompile all the asset (js and css), I only need application.css and application.js, as scaffolds.css and depot.css are concatenate in application.css. So scaffolds.css and depot.css are no longer needed in production.
How could I have the above code in dev and then in production, have asset pipeline know certain assets have been concatenated in application.css/js and then remove those asset link tag in the code?
If this is not possible, how should I avoid loading redundant resources and keeping prod deployment manageable? (meaning no deleting the link_tag manually in production)
Thanks.
You do not put
<%= stylesheet_link_tag "scaffolds" %>
<%= stylesheet_link_tag "depot", media: "all" %>
<%= stylesheet_link_tag "application", media: "all" %>
in your layout file. You only put
<%= stylesheet_link_tag "application", media: "all" %>
And in config/environment/development.rb you make sure you have
config.assets.debug = true
When config.assets.debug is set to true it will automatically generate the <link ... /> tags for each of your stylesheets in dev mode for each assets required in the application.css file's Sprockets directives.
In config/environment/production.rb config.assets.debug will be false by default, causing the assets to be concatenated together into a single application.css file (again, assuming your //= require lines are correct in application.css). This will cause 1 link tag to be created for only application.css in production.

Resources