Skip to content

Instantly share code, notes, and snippets.

@averyvery
Last active May 27, 2024 07:35
Show Gist options
  • Save averyvery/6e4576023b395de1aaf5 to your computer and use it in GitHub Desktop.
Save averyvery/6e4576023b395de1aaf5 to your computer and use it in GitHub Desktop.
Inline CSS or JS in Rails
config.assets.precompile += [
# precompile any CSS or JS file that doesn't start with _
/(^inline[^_\/]|\/[^_])[^\/]*.(js|css)$/,
...
def read_file_contents(stylesheet)
if %w(test development).include?(Rails.env.to_s)
# if we're running the full asset pipeline,
# just grab the body of the final output
stylesheet.body
else
# in a production-like environment, read the
# fingerprinted and compiled file
File.read(File.join(Rails.root, 'public', 'assets', stylesheet.digest_path))
end
end
def inline_file(asset_path)
file = Rails.application.assets.find_asset(asset_path)
file.nil? ? '' : read_file_contents(file)
end
def inline_js(asset_path)
"<script>#{inline_file asset_path}</script>"
end
def inline_css(asset_path)
"<style>#{inline_file asset_path}</style>"
end
# use a method like this to automatically load CSS that
# follows the current controller/action name structure
# example: assets/stylesheets/views/users/show.sass
def current_view_stylesheet
inline_css("views/#{params[:controller]}/#{params[:action]}") +
end
@wafiq
Copy link

wafiq commented Oct 27, 2015

Should stylesheet.body be stylesheet.source instead?

Source: https://github.com/rails/sprockets/blob/master/lib/sprockets/asset.rb#L26

@Dagnan
Copy link

Dagnan commented Jan 25, 2017

.source works for Rails 5.

@Dagnan
Copy link

Dagnan commented Jan 25, 2017

@dignoe
Copy link

dignoe commented Mar 3, 2017

FYI - I couldn't get this to work in Rails 3.2 with Sprockets 2.2.3. Here's what I did (created independently of this code, but posting here for anyone who needs some help):

module StylesheetsHelper

  private

  def include_inline_stylesheet(file)
    content_for :stylesheets do
      content_tag("style", inline_stylesheet_source(file).html_safe, type: "text/css")
    end
  end

  def inline_stylesheet_source(file)
    path = file.pathmap("%-1d")
    filename = File.basename(file, ".html.erb").titleize.parameterize

    if Rails.env.development? || Rails.env.test?
      Rails.application.assets["responsive/inline/#{path}/#{filename}"].body
    else
      asset_path = ActionController::Base.helpers.asset_path("responsive/inline/#{path}/#{filename}.css")
      File.read("#{Rails.root}/public#{asset_path}")
    end    
  end

end

And then in my views I add <%= include_inline_stylesheet(__FILE__) %> and I have a <%= yield :stylesheets %> in my <head>.
CSS files are in the format of responsive/inline/orders/index.css.scss (Note that this code replaces underscores with dashes in the filename, so my_file.html.erb becomes my-file.css).

@FinnWoelm
Copy link

This is genius. Thank you a lot, @averyvery and @Dagnan!

@wagoid
Copy link

wagoid commented Sep 25, 2017

@averyvery you could also leverage Rails cache when reading the file contents, replacing this:
File.read(File.join(Rails.root, 'public', 'assets', stylesheet.digest_path))
by this:
render file: File.join(Rails.root, 'public', 'assets', stylesheet.digest_path)

render here will return the actual string with the file contents, because it's being called from a view template 😃
That will avoid a lot of I/O operations and make your users happier!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment