Adam Pearlman
Adam Pearlman

Reputation: 1001

How do I render sass in a rails partial?

I have a Rails 3.2 app. I'm trying to render processed sass code in a partial.

I have added an initializer to handle scss files:

ActionView::Template.register_template_handler :scss,
  Sass::Rails::ScssTemplate

My sass file is called _style.scss and the render call looks like:

<%= render partial: "./templates/default/style", formats: "css" %>

I get the following error:

undefined method `call' for Sass::Rails::ScssTemplate:Class

To me, this looks like Rails doesn't know how to handle the Sass file, however, any .scss files included in my application.css file are processed correctly so, at least in that context, I know sass processing works. I've experimented with different extensions and formats. In some cases I can get the view to render, but sass is not processed.

Upvotes: 1

Views: 2023

Answers (2)

Chris O&#39;Sullivan
Chris O&#39;Sullivan

Reputation: 1272

I created a helper method to do this

def render_scss(file)
  text = render("/amp/#{file}")
  view_context = controller.view_context

  engine = Sass::Engine.new(text, {
    syntax: :scss, cache: false, read_cache: false, style: :compressed,
    sprockets:  {
      context:     view_context,
      environment: view_context.assets_environment
    }
  })
  raw engine.render
end

(Note: this includes the sprockets context to be able to handle the asset pipeline within your sass).

And then you call it like so (the scss is kept in a partial in the same directory called _amp.css.scss - not in the assets directory):

<style>
  <%= render_scss("amp.css.scss") %>
</style>

(Obviously this works for scss - but it's easy to change to apply to sass)

def render_sass(file)
  text = render("/amp/#{file}")
  view_context = controller.view_context

  engine = Sass::Engine.new(text, {
    syntax: :sass, cache: false, read_cache: false, style: :compressed,
    sprockets:  {
      context:     view_context,
      environment: view_context.assets_environment
    }
  })
  raw engine.render
end

The problem with this approach is that it it parsed at run time, however this can be got around by using standard Rails caching.

e.g.

<% cache(my_object) do %>
  <style>
    <%= render_scss("amp.css.scss") %>
  </style>
<% end %>

Note: in most normal situations you'll want to keep your stylesheets in a separate file. However there can be situations where this isn't appropriate. For example, I'm using this technique to build Google AMP pages where they forbid the stylesheet to be in a separate file.

Upvotes: 2

Richard Peck
Richard Peck

Reputation: 76774

Parsing

I think the problem will likely be to do with parsing

As you're calling a partial, Rails will typically try and render the pure HTML in the browser, with embedded erb code. If you're trying to call a css file in this way, I can only think that Rails will be unable to process the css in the same way

--

As mentioned in the comments, I would certainly use stylesheet_link_tag, as this will point to your CSS file in your HTML (which is how browsers process this anyway)

If you wanted to output the CSS itself, you'll have to define it inside an HTML file & then output that using a partial (as you're trying to do now)

Upvotes: 0

Related Questions