Write your Rails view in……. JavaScript?
In 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:
def index
@users = User.find(:all)
end
end
And my EJS view (the file is named index.html.ejs):
<%= user.first_name() %><br />
<% } %>
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:
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?
Posted by Aaron Patterson • Permalink • Leave your Comment »
Dr Nic says:
Does this get rendered on the server side? So the output of the example EJS template above would be just a list of names + with no “for” loops in sight?
Tuesday, 6 May 2008 @ 4:41pm
Aaron Patterson says:
Yes, you are correct. It is rendered on the server side just like ERb files.
Tuesday, 6 May 2008 @ 5:05pm
Alistair Holt says:
Interesting. But why would you do this?
Wednesday, 7 May 2008 @ 3:10am
Brian Takita says:
Very cool. There is also the Xmlbuilder javascript library which I use to render xml on the client side. Now I can use it on the server side.
http://pivotalrb.rubyforge.org/svn/xmlbuilder/trunk
The nice thing is you can have the power of client/server code (much easier to test and less rjs interactions with the server) while having the option to render the same objects on the server when the client/server architecture is not needed.
Thursday, 8 May 2008 @ 12:11am
win says:
I’m also wondering the point of doing this? Why not just view.js.erb and use Ruby?
On a side note I’ve been using TrimPath for a while to dynamically generate partials client side, works like a charm.
Friday, 9 May 2008 @ 8:21am
Aaron Patterson says:
I’m not generating anything on the client side. This is server side javascript. The javascript is actually executed on the server.
Friday, 9 May 2008 @ 8:25am
This Week in Ruby (May 12, 2008) | Zen and the Art of Programming says:
[...] screencast, that shows how to use Emacs with Rails. Other interesting highlights this week were: Write your Rails view in… JavaScript?, Community Engine (a Social Networking plugin), the release of El Dorado 0.9.2 (which adds a group [...]
Monday, 12 May 2008 @ 12:53pm