How to separate .scss by controller in Rails

As the scale of the application grows, the description of the application.scss file becomes longer, so I decided to separate the file for each controller this time. I had a lot of trouble and learned a lot, so I decided to write an article so that I wouldn't forget it.

environment

Ruby 2.5.7 Rails 5.2.4

answer

I will write only the answer first.

application.scss


// require_tree .
// require_self

erb:application.html.erb


<head>
  ...
  <%= stylesheet_link_tag 'application' %>
  ...
</head>

It's okay if you create this description and a .scss file for each controller name in app / assets / stylesheet /!

I will explain the contents a little from here.

Background

// require_tree. Is it necessary?

At first, I made application.scss a common style file, and tried to support all pages with two files of controller name.scss on each page. The description at that time is as follows.

application.scss


// require_self

erb:application.html.erb


<head>
  ...
  <%# application.loading scss%>
  <%= stylesheet_link_tag 'application' %>

  <%#Controller name.loading scss%>
  <%= stylesheet_link_tag params[:controller] %>
  ...
</head>

The // require_tree . in the application.scss file is a description that reads all the .scss files in app / assets / stylesheet, so delete it once. Instead, if you write params [: controller] in the stylesheet_link_tag of application.html.erb, you can get the path of the controller including the directory, so even if the controller is divided into directories, this writing method can be used.

However, this method is fine for .css files, but it causes an error for .scss.

Precompile fails

.scss can only be supported by browsers by compiling it into .css format. In other words, it usually cannot be displayed in .scss format.

And the precompiled .scss file (.css file) is stored under app / public / assets in the production environment, and the file name is changed to hash format. In other words, the css file cannot be picked up by <% = stylesheet_link_tag params [: controller]%> described in application.html.erb. Even if the file name is changed to the hash format, if you specify the hash as it is in the stylesheet_link_tag, it will work, but this hash is not realistic because it changes every time the file is updated.

I couldn't really get to the way I wanted to split the .scss file by controller, so I switched to the description at the beginning.

// About the difference between the presence and absence of require_tree.

If application.scss has // require_tree ., it means that all .scss files under assets / stylesheet will be loaded.

This shouldn't happen too much, but if you specify the style while the class name of the css selector is covered, the one described later will be given priority, so you can not change it as you want. By the way, there is a risk of creating dependencies.

.css (.scss) File reading order

application.scss


// require_tree .
// require_self

If you write it like the beginning, application.scss will be loaded after all .scss files have been loaded. Also, the order of the contents of // require_tree . is in dictionary order, and the files are read in the order of file name a → z. Inevitably, in tree., The closer the initial of the file name is to z, the later it will be read, so it tends to have a higher priority.

Handling of .scss files prepared for variables

Before that, let's take a look at the variables in .scss.

In scss, properties and values can be used as variables. For now in my case

_variables.scss


  //Hamburger animation
  $hamburger-transition: 0.3s;

  //Theme color
  $thema-color1: #fff9f9;
  $thema-color2: #ffefef;
  $thema-color-font: #555;

  //Media queries
  $media-sp-max: 450px;
  $media-pc-min: 1024px;
  $media-tb-min: $media-sp-max + 1px;
  $media-tb-max: $media-pc-min - 1px;

  //Example
Selector name{
    background: $thema-color1;
  }

With this, you can change the theme color, media query width, hamburger menu transition, etc. for each file at once.

You can define a variable by writing the variable name from $ and then entering the value. When calling, just write the variable name in place of the value.

However, as it is, the variable is not defined in each file, so you need to import the file that describes only this variable into the .scss file of each controller name.

Controller name.scss


@import "variables";
...

By describing @import" file name ", in this case, the variables written in _variables can be used.

The question arose here. "Application.scss describes // require_tree .. Each .scss file describes the import of variable files, so each time each file is read at compile time, the variable file is also described. Is it read as a .css file? " I can say that there is no problem even if it is read, but I thought that there was a lot of waste, so I investigated further.

The result was that I was avoiding it without knowing it. Lol

"Partial" to exclude common files from compilation

I made a file name by looking at some article and referring to how to make a variable file, but it seems that it will not be compiled by adding an "_" underscore at the beginning of the file name lol In other words, _variables.scss used this time is a file name that starts with an underscore, so it is excluded from precompilation. If you think about it carefully, it is true that files that only write variables do not style directly, so there is no point in converting to .css, and when converting other files to .css, replace the variable part with the contents. I was strangely convinced that if I could do it, the variable file would be enough.

Summary

I will return to the implementation method at the beginning, but for the time being, I am thinking of operating it in this way.

application.scss


// require_tree .
// require_self
...

_variables.scss


$Variable name:value;
...

Each controller name.scss


@import "variables";
...

erb:application.html.erb


<head>
  ...
  <%= stylesheet_link_tag 'application' %>
  ...
</head>

Until now, I wrote the style only in application.scss and made a block by writing the controller name by making full use of comments, but I wonder if it will be easier to maintain even if the file is separated for each controller. I think. In the unlikely event that the class name is covered, we will use the selector nesting, which is also a feature of .scss, to describe it visually in an easy-to-understand manner. (The class name for reuse (flex, grid, btn, etc.) is described separately in the application.scss file.)

I would appreciate it if you could teach me how to precompile the .scss file for each controller without using // require_tree .! Also, if you have any questions, differences in interpretation, or discomfort in the description method, we would appreciate it if you could point them out in the comments.

Thank you for reading until the end!

Reference site

Rails Guide-Asset Pipeline Web Design Leaves - SASS [CSS HappyLife --Let's learn Sass! Vol.7] Divide files for easier management (partial)](http://css-happylife.com/archives/2012/0124_1850.php) HACK NOTE --Sass: Let's manage variables in a separate file

Recommended Posts

How to separate .scss by controller in Rails
[Rails] How to write in Japanese
How to introduce jQuery in Rails 6
How to install Swiper in Rails
How to implement search functionality in Rails
How to change app name in rails
How to insert a video in Rails
How to use MySQL in Rails tutorial
[rails] How to configure routing in resources
How to implement ranking functionality in Rails
How to use credentials.yml.enc introduced in Rails 5.2
[Rails] How to decide the destination by "rails routes"
How to write Rails
How to implement a slideshow using slick in Rails (one by one & multiple by one)
[Rails] How to log in with a name by adding a devise name column
[Rails] How to use select boxes in Ransack
How to output CSV created by Rails to S3
How to translate Rails into Japanese in general
How to prevent direct URL typing in Rails
How to uninstall Rails
How to conditionally add html.erb class in Rails
How to implement a like feature in Rails
How to easily create a pull-down in Rails
How to use JQuery in js.erb of Rails6
[Ruby on Rails] How to install Bootstrap in Rails
How to make a follow function in Rails
[Rails] How to use PostgreSQL in Vagrant environment
How to check Rails commands in the terminal
How to set the display time to Japan time in Rails
[Rails] How to search by multiple values ​​with LIKE
How to implement guest login in 5 minutes in rails portfolio
How to remove the underline displayed by Rails link_to
Use Extend (Concerns) in Rails to standardize Controller processing.
[Ruby On Rails] How to reset DB in Heroku
[How to insert a video in haml with Rails]
How to write a date comparison search in Rails
How to query Array in jsonb with Rails + postgres
[Rails 6] How to set a background image in Rails [CSS]
[Rails] How to edit and customize devise view and controller
[Rails] How to load JavaScript in a specific view
[Rails] How to display an image in the view
[rails] How to post images
[Rails] How to use enum
[Rails] How to install devise
[Rails] How to use enum
How to read rails routes
How to use rails join
How to terminate rails server
How to write Rails validation
How to write Rails seed
[Rails] How to use validation
[Rails] How to disable turbolinks
[Rails] How to use authenticate_user!
[Rails] How to use "kaminari"
[Rails] How to implement scraping
[Rails] How to make seed
How to write Rails routing
[Rails] How to install simple_calendar
[Rails] How to install reCAPTCHA
[Rails] How to use Scope
How to separate words in names in classes, methods, and variables