Write your Rails view in....... JavaScript?
2008-05-06 @ 11:33In my last post about Johnson, I said that next time I would talk about the JavaScript parse tree that Johnson provides. Well, I changed my mind. Sorry.
I want to write about a rails plugin that I added to Johnson. Brohuda Katz wrote an ERb type parser in JavaScript, and added it to the (yet to be released) Johnson distribution. With that in mind, and looking at the new template handlers in edge rails, I was able to throw together a rails plugin that allows me to use JavaScript in my rails view code.
Lets get to the code. Here is my controller: ~~~ ruby class JohnsonController < ApplicationController def index @users = User.find(:all) end end ~~~
And my EJS view (the file is named index.html.ejs):
~~~ php
<% for(var user in at.users) { %>
<%= user.first_name() %>
<% } %>
~~~
The johnson rails plugin puts controller instance variables in to a special javascript variable called “at”. The “at” variable is actually a proxy to the controller, lazily fetching instance variables from the controller and importing those objects in to javascript land.
Lets take a look at the plugin, its only a few lines: ~~~ ruby class EJSHandler < ActionView::TemplateHandler class EJSProxy # :nodoc: def initialize(controller) @controller = controller end
def key?(pooperty)
@controller.instance_variables.include?("@#{pooperty}")
end
def [](pooperty)
@controller.instance_variable_get("@#{pooperty}")
end
def []=(pooperty, value)
@controller.instance_variable_set("@#{pooperty}", value)
end end
def initialize(view) @view = view end
def render(template) ctx = Johnson::Context.new ctx.evaluate(‘Johnson.require(“johnson/template”);’) ctx[‘template’] = template.source ctx[‘controller’] = @view.controller ctx[‘at’] = EJSProxy.new(@view.controller)
ctx.evaluate('Johnson.templatize(template).call(at)') end end
ActionView::Template.register_template_handler(“ejs”, EJSHandler) ~~~ When the template gets rendered (the render method), I wrap the controller with an EJS proxy, then compile the template into a javascript function, and call that function. The “at” variable is set to the EJSProxy before executing the template, and all property accessing on the “at” variable is passed along to fetching instance variables from the controller.
Server side javascript coding in rails. Weird, eh?