Beginning

People always have various tastes of color schemes in a web page. Recently, our development group clashed on the choice of theme color of the dashboard page. Even though we come to an agreement, users who are nearly thirty or forty years old may not care about it.

So, I make a decision, provide an option to switch color schemes by themselves.

Strange Situation

I make a key-value stored in the database, and just change xx.scss to xx.scss.erb, and assign variables with $primary-color: <%= # ruby codes %>;. I thought it would work. Absolutely not.

Actually, ruby codes in these files could be executed. But when the ruby variables changed, these assets were not affected at all! That’s to say, they were not recompiled!

Why?

Because Sprocket in rails takes charge of assets pipeline. they will be recompiled only when the contents of files included in assets pipeline change. Variables in these files did not change at all. Because what was changed are their values, not the contents of files.

Simply, a file contains a line

1
time = Time.now

Maybe the variable time will change as the time flies. But the content of this file never changes, it’s always a line of code, time = Time.now.

So, it will not be recompiled as variables’ values change.

Solve it

Then I visited the guide of Sprocket, and found nothing to solve this elegantly.

Now that it will be recompiled only when files change, I do it as it expects.

When the attribute of color scheme save, i.e. the callback of after_save, run the following code to rewrite _theme.scss.

1
2
3
4
5
def recompile_theme_assets
File.open("app/assets/stylesheets/partials/_theme.scss", 'w+') do |f|
f.write("$primary-color: #{self.value};")
end
end

And set down the following lines in the application.scss:

1
@import "partials/theme";

Then we can use the SCSS variable $primary-color to build assets.

When the data in the database changes, this file partials/_theme.scss will change. And application.scss will be recompiled because it imported this partial one.

That’s what we want.

But!

Something wrong in production environment!
Because the assets will be precompiled when deploying to production environment, the Sprocket will never be triggered any more. That’s to say, this way doesn’t make sense.

Another way to implement this function is manually compiling assets with ruby codes on ‘after_save’ callback. Unfortunately, I didn’t find any simple APIs to do it. The only way is to hack it, as some blogs said.

I choose to give it up.