Skip to content

Instantly share code, notes, and snippets.

@jamesr2323
Created May 12, 2020 15:30
Show Gist options
  • Save jamesr2323/57012b9867e1ad373e42df17e2b97e30 to your computer and use it in GitHub Desktop.
Save jamesr2323/57012b9867e1ad373e42df17e2b97e30 to your computer and use it in GitHub Desktop.
Dynamically change SASS in a multi-tenant Rails application
# This works by injecting SASS variables before the main template. As long as they are not
# redefined without !default later on you're good to go.
# Includes some local in-memory caching to not recompile SASS on every request.
# I've implemented it at the client (tenant) level, but it could equally be more granular, at
# level of some other entity in your application.
class AssetsController < ApplicationController
def styles
$stylesheets ||= {}
custom_variables = %Q{
$primary-color: #{@client.get_theme_primary_color};
$secondary-color: #{@client.get_theme_secondary_color};
$text-color: #{@client.get_theme_text_color};
}
hash = Digest::SHA256.hexdigest(custom_variables)
if Rails.env.development? # Efficiently determine if stylesheets have changed
hash += `find app/assets/stylesheets -type f -print0 | sort -z | xargs -0 md5sum | md5sum`.split(' ').first
end
if $stylesheets[hash].present?
css = $stylesheets[hash]
else
asset_source = custom_variables + File.read('app/assets/stylesheets/application.scss')
css = Sass::Engine.new(asset_source, {
syntax: :scss,
cache: false,
read_cache: false,
style: :compressed,
load_paths: [Rails.root.join('app', 'assets', 'stylesheets')]
}).render
$stylesheets[hash] = css
end
render body: css, content_type: 'text/css'
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment