Ruby 2.1 with Erubis Template Engine

Ruby 2.1 with erubis Template Engine

I ran benchmark between ERB and erubis rendering with below code snippet.

erubis_render_time =  Benchmark.realtime {

template_content = File.read("#{Rails.root}/app/views/web/email_templates/erubis_benchmark_test.erb")
1000.times do |j|
email_body = Erubis::Eruby.new(template_content).result({welcome_mail_cta: "Shop Now", welcome_mail_string: "Welcome. Your account is activated"})
end
}

template_path = "/web/email_templates/benchmark_test"
erb_render_time = Benchmark.realtime {
1000.times do |j|
email_body = ActionController::Base.new.send(:render_to_string,
:template => template_path,
:layout => false,
:locals => {:data => {welcome_mail_cta: "Shop Now",
welcome_mail_string: "Welcome. Your account is activated"
}
}
)
end
}

As per above benchmark suite Erubis is 10-15 times faster then ERB rendering.

Create your own tags/functions with Erubis

Those are just function calls that return the tag in a string:

def javascript_file( file_path )
"<script src=\"#{ file_path }\" type=\"text/javascript\"/>"
end

You just need to ensure that the functions are within scope at the time you call the binding.

Rendering tilt template using block as the scope

However, I succeeded when I used the standard ERB library like so:

proc = Proc.new do
@text = "Hello, World"
@num = 100
end

ERB.new('<%= @text %> | <%= @num %>').result proc.binding # => "Hello, World | 100"

If I insert the line, require 'erb' at the start of your code, and if I append 'p ' to your last line, the output I get is:

" | "

I tested that in rubies: 1.8.7, 1.9.3, 2.0, 2.1.

The reason @text and @num are nil is because they are not part of the proc's binding. First, the code in a block, like the code in a def, does not even execute until the block is called, so whether the proc is empty or has @ variables in it makes no difference if the proc is never executed.

Second, the only bindings (i.e. the variables and their values in the surrounding scope) that can be seen by your proc is self=main. And an @ variable attaches itself to whatever object is self when the @ variable springs into existence. As a result, when your proc does execute, the @ variables will fly away and attach themselves to main, which means they will have no association with your proc at all.

Third, you can't even change the value for self in the binding:

class Dog
def bark(proc_obj)
#self is a dog instance in here
proc_obj.call
p @text
end
end

my_proc = Proc.new{@text = "hello"}
Dog.new.bark my_proc

puts @text

--output:--
nil
hello

When the proc executes there is a variable named self in the surrounding scope, and its value is the dog instance--yet the @ variable in the proc attaches itself to self=main(the last puts statement shows that) rather than self=dog_instance. To me, that indicates that self acts like a local variable, and the proc closes over the local variable named self in the toplevel scope. Then, in the def ruby creates another local variable named self, which ruby sets equal to the dog instance that called the def. As a result, the toplevel self and the self in the def are two different variables, and therefore the value of the self in the def has no effect on the value the proc sees for self.

Finally, if you look at the docs for ruby 2.1, the Binding class now has a method for retrieving variables from the binding, and it's called local_variable_get(). Note the name local. There is no method named instance_variable_get() because as far as I can tell instance variables are not part of a binding--instead they fly away and attach themselves to some object, i.e. whatever self was equal to at the time the proc was created--not what self is equal to when the proc executes.

Rendering mailer templates with Mustache in Rails

Here is an example of using Stache with a mailer:

# config / initializers / stache.rb
Stache.configure do |c|
c.template_base_path = Rails.root.join('app', 'views')
c.wrapper_module_name = "Wrapper"

c.use :mustache
end

# app / mailers / registration_mailer.rb
class RegistrationMailer < ActionMailer::Base
default template_path: 'mailers/registration_mailer'

def bailed(user)
@user = user
mail to: user.email
end
end

# app / models / wrapper / mailers / regisration_mailer / bailed.rb
module Wrapper
module Mailers
module RegistrationMailer
class Bailed < ::Stache::Mustache::View
def continue_registration_link
link_to "Continue registration by connecting your Twitter account",
connect_registrations_url
end

def signature
@view.render "shared/mailer/sig"
end
end
end
end
end

I think what you are missing is the need to configure both the wrapper module and the template path.



Related Topics



Leave a reply



Submit