One of the features that several of the webapps I’ve worked on have had, is interactive consoles that allow you to enter some form of code, and see that run inside the webapp process itself. At Ning, we used jruby on rails for one of the admin apps, and it was a life saver to be able to execute debugging code on the app, and see exactly how the app itself was interpreting the code. At Apple, we have an interactive Groovy console that serves the same purpose.
So, when I was working on my latest app, I wanted to add the same piece of functionality. Here’s how I did it. It’s straight forward, and not too complicated, but it has a nice feature that I’ve added after my experience with the previous consoles I’ve used. One of the big drawbacks with the other consoles, was that you would end up hitting back and submit over and over as you refined your code. I wanted to minimize that in the spirit of . Here’s how I did it.
Add a new controller to your rails app (in this case, I named it console)
class ConsoleController < ApplicationController
helper :application
include ApplicationHelper
def index
end
def execute
begin
@script = params[:script]
rendering_start = Time.now
@output = eval(@script)
@rendering_time = ((Time.now - rendering_start)* 1000.0).to_i
rescue Exception => ex
@output = ex.inspect + "\n" + ex.backtrace.join("\n")
end
end
end
Then you’ll need to create the following views
views/console/_console_form.html.erb
<%= form_tag(console_path, :method => "post") do %>
<%= label_tag(:script, "Script:") %>
<br/>
<%= text_area_tag :script , @script || '', :size => "100x20" %>
<br/>
<%= submit_tag("Execute!") %>
<% end %>
views/console/index.html
<% content_for :right_bar do %> <p></p> <% end %> <%= render 'console_form' %>
views/console/execute.html
<!-- This will make the rails renderer send this output fragment to the 'yield :right_bar' block -->
<% content_for :right_bar do %>
<p><%= "Execution time: #{@rendering_time} milliseconds" %></p>
<% end %>
<%= render 'console_form' %>
<div id=console_output>
<pre>Script Output:
<%= @output %>
</pre>
</div>
You may be wondering what that content_for call is doing. In my app, I have a top bar, bottom bar (actually two of them, a right bar, and a left bar, and a center area that gets the main content). In this case, the right bar is getting the content from that call. It allows me to have a sort of context sensitive menu for each page (while I have a site wide menu on the left hand bar). I won’t muddy the waters by pasting my main layouts and css here, but you get the idea.
Now, the new page should be usable. After each execution, the edit box is prepopulated with the code you just submitted, so making corrections, or changes is very quick and easy. This will also tell you how long the script you just ran actually took (it’s not a hi-res timer, but it’s close enough for government work).
The really nice thing about this, is you can use your active record classes in here (or MongoMapper if you’re one of the cool kids). So, I can easily just run code like
User.find_by_id(5)[:username]
and see what my app will return for that database record.
It should be noted that this console can be very dangerous. There are no controls around deleting or updating data, so you need to be very careful about how you use this, and also make sure that you don’t expose this in any public site, as it’s sure to be abused at some point). I would add specific security checks for things like a specific user account, or Rails.env.development? ). I would probably also look at disabling this in the routes for the deployed app, just to be on the safe side.