rtomayko / tilt

Generic interface to multiple Ruby template engines

Home Page:http://github.com/rtomayko/tilt

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sprockets v3.7.0 deprecation warning

kamen-hursev opened this issue · comments

I use haml in some asset templates. After I updated Sprockets to v3.7. I got a deprecation warning:

DEPRECATION WARNING: You are using the a deprecated processor interface Tilt::HamlTemplate.
Please update your processor interface:
https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors

It seems to me this is not limited to Haml, but all template engines supported by Tilt. Is Tilt::Template supposed to implement self.call in order to support Sprockets v4?

The code that triggers the warning is a Rails initializer:

Rails.application.config.assets.configure do |config|
  config.register_mime_type 'text/html', extensions: ['.haml', '.html.haml']
  config.register_preprocessor 'text/html', Tilt::HamlTemplate
end

Sprockets was initially based on Tilt, but in the later versions they've decided to not make its interface compatible with Tilt. That is a completely fair decision as Tilt templates and Sprocket processors have different use cases.

There are no plans to change Tilt to be compatible with Sprockets v4. I think you can solve the problem by writing a class which implements call in redirects it to Tilt:

class TiltProcessor
  def initialize(template_class)
    @template_class = template_class
  end

  def call(input)
    # not sure if I've implemented this correctly
    result = @template_class.new(input[:filename]) { input[:data] }.render
    { data: result }
  end
end

config.register_preprocessor 'text/html', TiltProcessor.new(Tilt::HamlTemplate)

Thanks, @judofyr , for the code snippet. It (almost) works, just had to change the call method to:

def call(input)
  result = @template_class.new(input[:filename]) { input[:data] }.render
  { data: String.new(result) }
end

Because for some reason Sprockets insists the data is instance_of?(String) and in some cases I get ActiveSupport::SafeBuffer.

I encountered another problem. In the haml templates I use some view helpers and used to include them like:

Rails.application.config.assets.configure do |config|
  ...
  include ActionView::Helpers
  include Rails.application.routes.url_helpers
end

For some reason after using
config.register_preprocessor 'text/html', TiltProcessor.new(Tilt::HamlTemplate)
they are not included in the Haml processor and get errors like:
NoMethodError: undefined method 'image_tag'. Do you have any idea how this can be solved?

You could maybe do something like this:

class TiltProcessor
  def initialize(template_class)
    @template_class = template_class
  end

  def context
    @context ||= Object.new
  end

  def call(input)
    result = @template_class.new(input[:filename]) { input[:data] }.render(context)
    { data: result }
  end
end

And then you can extend it into the context:

processor = TiltProcessor.new(Tilt::HamlTemplate)
processor.context.extend Rails.application.routes.url_helpers
config.register_preprocessor 'text/html', processor

@judofyr, thank you very much for helping me with this!
Just a note that extend won't work with modules like ActionView::Helpers. So the final solution that works for me is:

class TiltProcessor
  def initialize(template_class, context = nil)
    @template_class = template_class
    @context = context || Object.new
  end

  def call(input)
    result = @template_class.new(input[:filename]) { input[:data] }.render(@context)
    { data: String.new(result) }
  end
end

class HamlAssetsContext
  include SimpleForm::Helpers
  include SimpleForm::ActionViewExtensions::FormHelper
  include ActionView::Helpers
  include Rails.application.routes.url_helpers
  # Include any other view helper module that you need. eg:
  # include ApplicationHelper
end

Rails.application.config.assets.configure do |config|
  config.register_mime_type 'text/html', extensions: ['.haml', '.html.haml']
  processor = TiltProcessor.new(Tilt::HamlTemplate, HamlAssetsContext.new)
  config.register_preprocessor 'text/html', processor
end

Very happy you found a solution :) I'm closing this issue now. Feel free to reopen or comment if you have any other issues/questions.

(One tiny suggestion: Change the initializer to def initialize(template_class, context = Object.new))

The above solution has some issues related with the context. For example image_tag, would not render correct URL-s with the hashed tail.

After some more research I managed to find my way around to sprockets legacy_tilt_processor.rb. Adding the final version here, just in case this issue attracts more people with the same/similar problem.

# For Rails add to a file in config/initializers
class TiltProcessor
  def initialize(klass)
    @klass = klass
  end

  def call(input)
    filename = input[:filename]
    data     = input[:data]
    context  = input[:environment].context_class.new(input)

    data = @klass.new(filename) { data }.render(context, {})
    context.metadata.merge(data: data.to_str)
  end
end

Rails.application.config.assets.configure do |env|
  env.context_class.class_eval do
    include SimpleForm::Helpers
    include SimpleForm::ActionViewExtensions::FormHelper
    include ActionView::Helpers
    include Rails.application.routes.url_helpers
    # Include any other view helper module that you need. eg:
    # include ApplicationHelper
  end

  env.register_mime_type 'text/html', extensions: ['.haml', '.html.haml']
  env.register_preprocessor 'text/html', TiltProcessor.new(Tilt::HamlTemplate)
end

Just don't understand why the Sprockets' processor class needs to inherit Delegator.