0


I have an Informations model which has a plain_keywords attribute. When this attribute is updated, I would like to precompile my SASS stylesheets because there is a certain SASS variable which is computed in terms of this attribute. This question seemed similar to mine so I did this:

Gemfile

gem 'rake'


config/initializers/rake.rb

Rake.load_rakefile Rails.root.join('Rakefile')


app/models/informations.rb

require 'rake'

class Informations < ApplicationRecord

    after_save :precompile, if: :plain_keywords_changed?

    private
        def precompile
            Rake::Task['assets:precompile'].invoke
        end
end


The precompile method is actually called when the plain_keywords attribute is updated, but my stylesheets look unchanged.

Do you have any idea ?


Edit:

To answer the question Why do I want to do that ?, the keywords contained in the plain_keywords attribute are animated by CSS to make them scroll. But the animation need to have a $keywords-length SASS variable to be computed, in order to be perfectly homogeneous and with the same duration for each keywords.

I got that it is actually a wrong idea to precompile my stylesheets each time this attribute is updated.

So I created a stylesheets controller which has a keywords action. It generates just the dynamic part of the CSS animation:

class StylesheetsController < ApplicationController
    def keywords
        length = Informations.first.keywords.length # There is only one record for Informations
        duration = 2.0
        transition = 0.4
        height = 40
        animation_duration = (duration + transition)*length

        css = '.keywords strong {animation: keyword '+animation_duration.to_s+'s infinite}'

        length.times do |n|
            css += '.keywords strong:nth-of-type('+(n + 1).to_s+'){animation-delay:'+(-n*(transition + duration)).to_s+'s}'
        end

        css += '@keyframes keyword{'

        [
            {
                p: 0,
                properties: {
                    opacity: 0,
                    transform: 'translateY('+((-height).to_s)+'px) rotateX(90deg)',
                    :'transform-origin' => 'center bottom'
                }
            },
            {
                p: transition/animation_duration,
                properties: {
                    opacity: 1,
                    transform: 'translateY(0) rotateX(0)',
                    :'transform-origin' => 'center bottom'
                }
            },
            {
                p: (transition + duration)/animation_duration,
                properties: {
                    opacity: 1,
                    transform: 'translateY(0) rotateX(0)',
                    :'transform-origin' => 'center top'
                }
            },
            {
                p: (transition*2 + duration)/animation_duration,
                properties: {
                    opacity: 0,
                    transform: 'translateY('+height.to_s+'px) rotateX(-90deg)',
                    :'transform-origin' => 'center top'
                }
            },
            {
                p: 1,
                properties: {
                    opacity: 0,
                    transform: 'translateY('+height.to_s+'px) rotateX(-90deg)',
                    :'transform-origin' => 'center top'
                }
            }
        ].each do |keyframe|
            css += (keyframe[:p]*100).to_s+'%{'
            css += keyframe[:properties].to_a.map{ |v| v.join ':' }.join ';'
            css += '}'
        end

        css += '}'

        render text: css, content_type: 'text/css'
    end
end
Julien Dargelos
  • 356
  • 1
  • 12
  • you might need to do clobber first – Pavel S Mar 10 '17 at 12:51
  • 3
    I feel like this should not be done at all. Asset precompiling should happen once before deployment and not in production. I would rethink what you have done so far. Can't you just choose a CSS class based on the `Informations` model or something similar? – AmShaegar Mar 10 '17 at 13:40
  • As stated by @AmShaegar, once assets are precompiled, since they are static, they shouldn't be modified. Instead, you could generate some dynamic css style and place it on the rendered view, or serve it via HTTP (in json or plain text), and process it via javascripts, adding it to the page once it's loaded. Remember that you can [edit CSS on runtime](http://stackoverflow.com/questions/1720320/how-to-dynamically-create-css-class-in-javascript-and-apply). – Wikiti Mar 10 '17 at 14:34
  • Are you expecting different users to get different styles (themes)? This wouldn't be the way to do that, everyone will see the same styles. – Marc Rohloff Mar 10 '17 at 18:24

0 Answers0