This guide will show you how you can use JRuby to run any Rack application inside Google Web Toolkit’s (GWT) hosted mode server so your interface and your backend are of the Same Origin.
BackgroundThe solution
Since I wanted to develop using GWT’s development environment with a Rack backend, I devised a way to use jruby-rack to load arbitrary Rack applications alongside our interface.
wget http://google-web-toolkit.googlecode.com/files/gwt-linux-1.7.0.tar.bz2tar -xvjpf gwt-linux-1.7.0.tar.bz2cd gwt-linux-1.7.0
2 .Download the latest jruby-complete.jar:
wget http://repository.codehaus.org/org/jruby/jruby-complete/1.3.1/jruby-complete-1.3.1.jarmv jruby-complete-1.3.1.jar jruby-complete.jar
3. Download the latest jruby-rack.jar
wget http://repository.codehaus.org/org/jruby/rack/jruby-rack/0.9.4/jruby-rack-0.9.4.jarmv jruby-rack-0.9.4.jar jruby-rack.jar
Now let’s create our GWT application using an example Sinatra backend:
4. Create an app with webAppCreator:./webAppCreator -out MySinatra com.example.MySinatracd MySinatra
5. In order for this to work you have to package any gem dependencies your backend needs (sinatra, in our case) as jars within your application. For Sinatra it looks like this:
java -jar jruby-complete.jar -S gem install -i ./sinatra sinatra --no-rdoc --no-ri jar cf sinatra.jar -C sinatra .
6. Add jruby-complete.jar, jruby-rack.jar, sinatra.jar (and any other jars you’ve created) to the libs target of your build.xml:
<target name="libs" description="Copy libs to WEB-INF/lib"> <mkdir dir="war/WEB-INF/lib" /> <copy todir="war/WEB-INF/lib" file="${gwt.sdk}/gwt-servlet.jar" /> <!-- Add any additional server libs that need to be copied --> <copy todir="war/WEB-INF/lib" file="${gwt.sdk}/jruby-complete.jar" /> <copy todir="war/WEB-INF/lib" file="${gwt.sdk}/jruby-rack.jar" /> <copy todir="war/WEB-INF/lib" file="${gwt.sdk}/sinatra.jar" /> </target>7. Add these lines right after <web-app> in war/WEB-INF/web.xml:
<context-param> <param-name>rackup</param-name> <param-value> require 'rubygems' require './lib/sinatra_app' map '/api' do run MyApp end </param-value> </context-param> <filter> <filter-name>RackFilter</filter-name> <filter-class>org.jruby.rack.RackFilter</filter-class> </filter> <filter-mapping> <filter-name>RackFilter</filter-name> <url-pattern>/api/*</url-pattern> </filter-mapping> <listener> <listener-class>org.jruby.rack.RackServletContextListener</listener-class> </listener>
Note: All you’re doing here is passing the contents of a config.ru file into the <param-value> element for the <context-param> (make sure this is HTML encoded!). This states that any request to /api is to be handled by your Sinatra application and not GWT’s Hosted mode servlet.
8. Create your Sinatra backend and place it in war/WEB-INF/lib/sinatra_app.rbrequire 'sinatra'require 'open-uri'class MyApp < Sinatra::Base get '/showpage' do open('http://www.yahoo.com').read end get '/helloworld' do 'hello world' endend9. Run your new awesome setup:
ant hosted
Now when navigate to http://localhost:8888/api/helloworld or http://localhost:8888/api/showpage you should see the Sinatra application being served via GWT.
Even though I have been using Rails for fun and profit for about 2 years now, I felt I never really used it’s routing engine to its full potential. So I checked out new Rails Routing from the outside in guide and discovered bunch of useful tricks that I (and maybe you) had no idea you could do. Here they are:
map.resources :photos, :books, :videos
map.resources :photos, :requirements => { :id => /[A-Z][A-Z][0-9]+/ }
This way, /photos/3 would not work, but /photos/DA321 would.
Say for your application ‘create’ and ‘change’ make more sense than the default ‘new’ and ‘edit’ you can do
map.resources :photos, :path_names => { :new => 'make', :edit => 'change' }You can also do this site-wide also, in your environment.rb
config.action_controller.resources_path_names = { :new => 'make', :edit => 'change' }When you use map.resources, rails generates 7 restful routes for that resource; But what if that resource only needed to be seen and listed, never edited or created?
map.resources :photos, :only => [:index, :show]
If your application uses alot of map.resources calls but not neccesarily all its generated routes, you can save memory this way.
Instead of fighting the map.resources generator by placing a horror like this atop your routes.rb
map.connect '/photos/:id/preview', { :controller => 'photos', :action => 'preview' }
You can do this to your already mapped resource
map.resources :photos, :member => { :preview => :get }
This will map all GET’s to /photos/3 to the preview action of your photos controller
map.resources :photos, :collection => { :search => :get }This will give you /photos/search and hit the search action within the photos controller
I stumbled upon http://clickthatbutton.com during my routine lurking of hacker news. After being amused for about 10 seconds, I decided to take it to the next level; I wanted to click on it really, really fast. After going through a few solutions (simple js while loop in firebug, then curl/wget) and failing, the idea of using selenium popped into my head. So I went off to their site and installed the extension. I figured a simple recording of the mouse event, then wrapping it around a loop in selenium would do the trick, but I quickly found that selenium doesn’t support loops. Not to be stopped, I searched google and ended up with this. After installing the plugin for selenium (a plugin for a plugin!?) and restarting firefox, I tried it again and to my surprise it worked! The click counter was going up steadily on its own (18k clicks and counting). Here is my selenium test case for those of you following along:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://clickthatbutton.com/" />
<title>haha</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">haha</td></tr>
</thead><tbody>
<tr>
<td>open</td>
<td>/</td>
<td></td>
</tr>
<tr>
<td>store</td>
<td>x</td>
<td>1</td>
</tr>
<tr>
<td>while</td>
<td>storedVars['x'] == storedVars['x']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>submit</td>
<td></td>
</tr>
<tr>
<td>endWhile</td>
<td></td>
<td></td>
</tr>
</tbody></table>
</body>
</html>Just paste that into a file, open it with selenium ide, hit play and you should be good to go.
Here is a class for enabling the use of arrow keys to navigate through a grid of input fields: (using mootools)
var FocusMover = new Class({
initialize: function(sel, col_num){
this.sel = sel
this.col_num = col_num
this.inputs = $$(this.sel)
this.current_focus = 0
var self = this
this.inputs.each(function(item, index){
item.addEvent('keydown',function(key){
$try(function(){
self[key.key]()
})
})
item.addEvent('focus',function(e){
self.refresh(e)
})
item.set('myid', index)
})
this.inputs[0].focus()
},
refresh: function(e){
this.current_focus = e.target.get('myid')
},
down: function(){
i = parseInt(this.current_focus) + parseInt(this.col_num)
this.inputs[i].focus()
},
up: function(){
i = parseInt(this.current_focus) - parseInt(this.col_num)
this.inputs[i].focus()
},
left: function(){
i = parseInt(this.current_focus) - 1
this.inputs[i].focus()
},
right: function(){
i = parseInt(this.current_focus) + 1
this.inputs[i].focus()
}
})As you can see, the constructor takes two arguments: a selector (which should return a list of all your input fields), and the number of input field columns. So for a 4x2 table, you would set it up like this:
var FM = new FocusMover('#mytable input', 4)Sometimes it’s useful to switch the browser’s default tabbing behavior (left to right) to the opposite (top to bottom) when your input fields are in a grid layout instead the of the usual single column layout. Having to do this manually is a real pain, especially for large grids; So here is a solution in javascript, using mootools:
window.addEvent('domready', function(){
var trs = $$('#mytable tr')
var accum = 0
trs.each(function(tr, trindex){
accum = trindex + 1
tr.getChildren().each(function(td, tdindex){
td.getChildren('input')[0].tabIndex = accum
accum = accum + trs.length
})
})
})I’ve been toying around with MooTools a bit lately, and I’ve found the experience quite enjoyable and refreshing. Naturally, I twittered about it and went along my merry way. Moments later (and much to my surprise), I had a direct message from John Resig himself asking “Why, what’s wrong with jQuery?”. I was pretty taken aback that he would take time from his surely busy day to message a total stranger in an effort to improve his project or at least gain an insight in the everyday life of a js developer (it’s not like DHH would personally message people that are dumping rails to use merb). I figured he deserved a straight, honest answer; One that at least would be longer than 140 characters (even though I managed to use every single one). So it begs the question, Why MooTools?
It’s not like I’m never going to use JQuery again; It simply isn’t my default js framework any longer.
I would buy and frame this.
This is common pattern in website navigation, where it highlights the link (usually by setting class=”active”) that took you to the current page while you are on that page.
First, define a helper:
def is_active?(page_name)
"active" if params[:action] == page_name
endThen call it in your link_to’s in your layout as such:
link_to 'Home', '/', :class => is_active?("index")
link_to 'About', '/about', :class => is_active?("about")
link_to 'contact', '/contact', :class => is_active?("contact")This effect is achieved due to how link_to handles being passed nil for its :class, so when is_active? returns nil (because its not the current page), link_to outputs nothing as its class (not class=”” as you might expect).
good git server tutorial, http://blog.commonthread.com/2008/4/14/setting-up-a-git-server