From the code you have posted above, it seems like you are trying to
implement css themes in Rails app. If you, here is how I have
implemented the theme feature in my application.
Whenever admin makes changes to theme file and updated it, a
compiled css file gets generated/updated in the
public/assets/themes/ folder with the theme name. That file is
picked up by the application based on current theme applied. (I can
provide code if this is what you are looking for.)
To serve assets to only some specific pages, you need to implement some kind of logic that loads assets based on it. For eg. Controller Specific assets: check here.
Update for Option 1
I have Theme resource in which I save theme name and two theme colors (you can use more).
Here is how my view form looks like:
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :color1 %><br>
<%= f.text_field :color1 %>
</div>
<div class="field">
<%= f.label :color2 %><br>
<%= f.text_field :color2 %>
</div>
Here is how my ThemesController File looks like:
class ThemesController < ApplicationController
after_action :compile_theme, only: [:create, :update]
THEME_PATH = 'app/assets/'
PATH = THEME_PATH + '/themes'
def new
@theme = Theme.new
end
def edit
@theme = Theme.find(params[:id])
end
def create
@theme = Theme.new(theme_params)
if @theme.save
# Create a scss theme file
write_theme_file
redirect_to @theme, notice: 'Theme was successfully created.'
else
render :new
end
end
def update
@theme = Theme.find(params[:id])
if @theme.update(theme_params)
# Create/Update a scss theme file, you can check for file exists
write_theme_file
redirect_to @theme, notice: 'Theme was successfully updated.'
else
render :edit
end
end
private
def write_theme_file
file = PATH + name + '.scss'
body = "$color1: #{@theme.color1};\n$color2: #{@theme.color2};"
File.write(file, body)
end
def compile_theme
file = PATH + name + '.scss'
theme_body = ''
if File.exists?(file) && File.exists?(THEME_PATH + 'theme.scss')
file = File.open(file)
theme_body = file.read
file.close
file = File.open(THEME_PATH + 'theme.scss')
theme_body = theme_body + file.read
file.close
else
colors = ''
end
env = if Rails.application.assets.is_a?(Sprockets::Index)
Rails.application.assets.instance_variable_get('@environment')
else
Rails.application.assets
end
Dir.mkdir(Rails.root + 'public/assets/themes') unless Dir.exists?(Rails.root + 'public/assets/themes')
asset_file = File.join(Rails.root, 'public', asset_path(name))
File.delete(asset_file) if File.exists?(asset_file)
body = ::Sass::Engine.new(theme_body, {syntax: :scss, cache: false, read_cache: false, style: :compressed}).render
File.write(File.join(Rails.root, 'public', asset_path(name)), body)
end
def asset_path(name)
digest = Digest::MD5.hexdigest(name)
"assets/themes/#{name}-#{digest}.css"
end
def name
return @theme.name.downcase
end
def theme_params
params.require(:theme).permit(:name, :color1, :color2)
end
end
Explanation of controller methods:
When a new theme is created or updated, it stores the theme and creates a new .scss file inside app/assets/themes with the theme name and defined color values.
The compilation and creation of css asset file happens after create/update action is completed. The compile_theme method looks for a theme.scss (example at the bottom) file (which I have already created inside app/assets/stylesheets/ folder with basic theme color variables) and replaces $color1 and $color2 variables with color values from the current theme file. The resulting css data is being hold in theme_body variable.
body = ::Sass::Engine.new(theme_body, {syntax: :scss, cache: false, read_cache: false, style: :compressed}).render
File.write(File.join(Rails.root, 'public', asset_path(name)), body)
These two last lines will create a new file inside public/assets/themes with the resulting theme_body css content and file name with theme_name and digest.
Now you need to pick up the file in every page. To do that, in application_controller.rb file, define this
before_filter :set_theme
private
def set_theme
@theme = Theme.first # or change theme according to params
end
And finally, you need to pickup the theme file in your layout file. So, add this in layouts/application.html.erb file:
<% if @theme.present? %>
<% digest = Digest::MD5.hexdigest(@theme) %>
<%= stylesheet_link_tag asset_url("assets/themes/#{@theme}-#{digest}.css") %>
<% end %>
Just for reference, here is how my theme.scss file looks like:
body {
background-color: $color1;
}
#header-wrapper, footer {
background-color: $color2;
}
That's all. Hope this helps. Let me know if you got any issues.
http://localhost:3000/vendor/assets/stylesheets/application.css
– dr. strange