My favorites | Sign in
Logo
             
Search
for
Updated Nov 03, 2009 by mando.woodie
Labels: Featured
GettingStarted  
Getting Started with JRuby on Google App Engine

If you have issues please see the Google Group.

Hello, World

# Install the google-appengine gem
# Do not use JRuby. App Engine will automatically use JRuby when necessary.
$ sudo gem install google-appengine

# Create a simple app
$ mkdir hello; cd hello; cat >config.ru <<EOF
require 'appengine-rack'
AppEngine::Rack.configure_app(		
    :application => "application-id",		
    :version => 1)
run lambda { Rack::Response.new("Hello World!").finish }
EOF

# Start development server
$ dev_appserver.rb .

Building a guestbook using Sinatra

# assign gems to your application
$ cat >Gemfile <<EOF
# Critical default settings:
disable_system_gems
disable_rubygems
bundle_path ".gems/bundler_gems"
# List gems to bundle here:
gem "dm-appengine"
gem "sinatra"
EOF

# Update config.ru to use Sinatra
$ cat >config.ru <<EOF
require 'appengine-rack'
AppEngine::Rack.configure_app(
  :application => 'application-id',
  :version => 1)
require 'guestbook'
run Sinatra::Application
EOF

Now write your application in guestbook.rb:

require 'sinatra'
require 'dm-core'

# Configure DataMapper to use the App Engine datastore 
DataMapper.setup(:default, "appengine://auto")

# Create your model class
class Shout
  include DataMapper::Resource
  
  property :id, Serial
  property :message, Text
end

# Make sure our template can use <%=h
helpers do
  include Rack::Utils
  alias_method :h, :escape_html
end

get '/' do
  # Just list all the shouts
  @shouts = Shout.all
  erb :index
end

post '/' do
  # Create a new shout and redirect back to the list.
  shout = Shout.create(:message => params[:message])
  redirect '/'
end

And now for the template. Create views/index.erb:

<% @shouts.each do |shout| %>
<p>Someone wrote, <q><%=h shout.message %></q></p>
<% end %>

<form method=post>
<textarea name="message"></textarea>
<input type=submit value=Shout>
</form>

Uploading your app

# Create an application-id at appspot.com:
> http://appengine.google.com/start/createapp

# Replace the application-id in config.ru
> :application => "your-app-id"

# Upload to App Engine
$ appcfg.rb update .

# It should now be running at http://your-app-id.appspot.com

Comment by PanosJee, Jun 25, 2009

hey, i attended the JRuby on GAE today and i have a questions. Is it possible to use the user library within JRuby so I can easily login as administrator?

Comment by ribrdb, Jun 26, 2009

Do you mean the AppEngine? user API? The appengine-apis gem includes a JRuby version of the users API: http://appengine-jruby.googlecode.com/svn/trunk/rdoc/appengine-apis/classes/AppEngine/Users.html

Comment by tim.inman, Aug 02, 2009

FYI I had to change:

post '/' do

shout = Shout.create(:message => params:message?) redirect '/'
end

to:

post '/post' do

shout = Shout.create(:message => params:message?) redirect '/'
end

to get it working.

Comment by tim.inman, Aug 04, 2009

Sorry to be a pain, but this will work with Merb, right? Could we possibly have an example of a merb app?

Comment by tteulings, Aug 04, 2009

I'm getting the following error:

IO error -- guestbook from config.ru:3 You're seeing this error because you use Rack::ShowStatus?.

My config.ru looks like this:

require 'appengine-rack' require 'guestbook'

AppEngine?::Rack.configure_app(
:application => "automatique-site", :version => 1)
run Sinatra::Application

It does run on the appserver locally so not sure what wrecking the havoc...

Comment by PanosJee, Aug 04, 2009

Is there any reason to use these tools rather than other methods using Warble and so on? I do not see where this methods bundles gems to the lib and so on

Comment by ribrdb, Aug 10, 2009

This bundles your gems when you run appcfg.rb gem install ...

You can use warbler if you prefer, but this is currently the recommended way. For one thing this makes it much easier to test your app locally, since you don't have to bundle your app and run from a war file.

Comment by locke2053, Aug 11, 2009

Two problems with this guide:

First, installing the google-appengine gem gives the error:

`C:\dev>gem install google-appengine Successfully installed google-appengine-0.0.1 1 gem installed Installing ri documentation for google-appengine-0.0.1... File not found: lib`

Does this error mean trouble? I have no idea.

Second, the appengine-rack example fails to mention that one must first do a

gem install appengine-rack

Platform: jruby 1.3.1 and Java 1.6.0_16-b01 64b installed and working on Vista 64.

Thanks for supporting ruby! I very much hope you get the chance to do a step-by-step, from-scratch walk through of getting jruby working with app engine.

Comment by trejkaz, Aug 15, 2009

The Hello World instructions were helpful, and aside from the need for appengine-rack, worked for me (maybe this should be set up as a gem dependency?)

A further howto on hooking this into Rails would be useful, but I suspect there will be a blog around somewhere which covers this.

Comment by ambientideas, Aug 17, 2009

I'm using JRuby 1.3.1 (brand new, clean) and am following the howto. I'm using AppEngine? SDK 1.2.2. I have it pointed to by the Google-recommended APPENGINE_HOME environment var.

After installing the Gems suggested in the how-to, when trying the Sinatra app demo (latest source code) via:

dev_appserver.rb .

I get the following error:

=> Booting DevAppServer? => Press Ctrl-C to shutdown server => Generating configuration files /Applications/Dev/jruby-1.3.1/lib/ruby/gems/1.8/gems/appengine-apis-0.0.8/lib/appengine-apis/datastore_types.rb:115:in `const_missing': cannot load Java class com.google.appengine.api.datastore.Key (NameError?)

from /Applications/Dev/jruby-1.3.1/lib/ruby/gems/1.8/gems/appengine-apis-0.0.8/lib/appengine-apis/datastore_types.rb:120

So I started looking for this Key class. Indeed, it lives in appengine-api.jar, as I manually confirmed.

The rack demo works just fine, so I know the AppEngine? SDK is at least being found.

Any suggestions or locations to go for help?

References: http://groups.google.com/group/appengine-jruby/browse_thread/thread/715c1d5d783b1590 http://code.google.com/p/appengine-jruby/source/browse/appengine-sdk/appengine-sdk.erb?spec=svn1aed5074bc960fd3d1b524c1b6aea67472bd9348&r=1aed5074bc960fd3d1b524c1b6aea67472bd9348

Comment by locke2053, Aug 18, 2009

Anyone have any info on how to use Google's URLFetch API from within JRuby?

Comment by aznaum, Aug 18, 2009

Anyone have any info on how to use Google's URLFetch API from within JRuby?

  require 'appengine-apis/urlfetch'
  Net::HTTP = AppEngine::URLFetch::HTTP
  hdoc = Net::HTTP.get(URI.parse("http://tumblr.com"))
Comment by locke2053, Aug 19, 2009

Aznaum, adding "require 'appengine-apis/urlfetch' yields:

$ dev_appserver.rb . => Booting DevAppServer? => Press Ctrl-C to shutdown server => Installing JRuby => Generating configuration files /usr/local/jruby-1.3.1/lib/ruby/site_ruby/1.8/builtin/javasupport/core_ext/object.rb:116:in `get_proxy_or_package_under_package': cannot load Java class com.google.appengine.api.urlfetch.URLFetchServiceFactory (NameError?)

from /usr/local/jruby-1.3.1/lib/ruby/site_ruby/1.8/builtin/javasupport/java.rb:51:in `method_missing' from ./urlfetch.rb:5 from ./urlfetch.rb:31:in `require' from /usr/local/jruby-1.3.1/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require' from ./nick-brown.rb:3 from ./nick-brown.rb:31:in `require' from /usr/local/jruby-1.3.1/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require' from config.ru:4:in `generate_xml'

Comment by aznaum, Aug 19, 2009

@locke2053

Are you up to date with latest gem versions?

$ appcfg.rb gem list

*** LOCAL GEMS ***

addressable (2.1.0)
appengine-apis (0.0.8)
dm-appengine (0.0.3, 0.0.2)
dm-core (0.10.0)
extlib (0.9.13)
maruku (0.6.0)
rack (1.0.0)
sinatra (0.9.4)
syntax (1.0.0)

$ appcfg.rb run -S irb

irb(main):001:0> require 'myapp'
=> true

irb(main):002:0> require 'appengine-apis/urlfetch'
=> false

irb(main):003:0> Net::HTTP = AppEngine::URLFetch::HTTP
(irb):4 warning: already initialized constant HTTP
=> Net::HTTP

irb(main):004:0> hdoc = Net::HTTP.get(URI.parse("http://www.biblegateway.com/"))
Aug 19, 2009 6:39:56 PM org.apache.commons.httpclient.HttpMethodBase getResponseBody
WARNING: Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.
=> "<!DOCTYPE…
irb(main):005:0> 
Comment by tr...@phamcom.com, Aug 20, 2009

How does DataStore? work in development? I can't seem to save or query anything when running locally?

And where is the log file when running locally?

Comment by locke2053, Aug 21, 2009

aznaum, I really think the appengine-apis gem is broken. I have tried this on multiple systems, some Windows, some Linux. Everything works fine unless I try to use appengine-apis. Perhaps you had to do something to make it work on your machine which isn't documented anywhere? Here's an example from a Windows XP 32 system:

C:\appengine>jruby -v
jruby 1.3.1 (ruby 1.8.6p287) (2009-06-15 2fd6c3d) (Java HotSpot(TM) Client VM 1.6.0_15) [x86-java]

C:\appengine>appcfg.rb.bat gem list

*** LOCAL GEMS ***

addressable (2.1.0, 2.0.2)
appengine-apis (0.0.8)
appengine-jruby-jars (0.0.2)
appengine-rack (0.0.2)
appengine-sdk (1.2.2)
appengine-tools (0.0.2)
data_objects (0.9.12)
dm-core (0.9.11)
extlib (0.9.12)
google-appengine (0.0.2)
maruku (0.6.0)
rack (1.0.0)
sinatra (0.9.4)
syntax (1.0.0)

C:\appengine>type config.ru
require 'appengine-rack'
#require 'appengine-apis/urlfetch'
AppEngine::Rack.configure_app(
    :application => "application-id",
    :version => 1)
run lambda { Rack::Response.new("Hello World!") }
C:\appengine>dev_appserver.rb.bat .
=> Booting DevAppServer
=> Press Ctrl-C to shutdown server
=> Installing JRuby
=> Retrieving jruby-rack
=> Installing appengine-sdk
=> Generating configuration files
The server is running at http://localhost:8080/
^C
Terminate batch job (Y/N)? y

[[[ here i uncomment the appengine-apis line ]]]

C:\appengine>type config.ru
require 'appengine-rack'
require 'appengine-apis/urlfetch'
AppEngine::Rack.configure_app(
    :application => "application-id",
    :version => 1)
run lambda { Rack::Response.new("Hello World!") }
C:\appengine>dev_appserver.rb.bat .
=> Booting DevAppServer
=> Press Ctrl-C to shutdown server
=> Generating configuration files
C:/jruby-1.3.1/bin/../lib/ruby/1.8/rexml/encodings/UTF-8.rb:31:in `get_proxy_or_package_under_package': cannot load Ja
va class com.google.appengine.api.urlfetch.FetchOptions (NameError)
        from C:/jruby-1.3.1/bin/../lib/ruby/site_ruby/1.8/builtin/javasupport/java.rb:51:in `method_missing'
        from C:/jruby-1.3.1/lib/ruby/gems/1.8/gems/appengine-apis-0.0.8/lib/appengine-apis/urlfetch.rb:34
        from C:/jruby-1.3.1/lib/ruby/gems/1.8/gems/appengine-apis-0.0.8/lib/appengine-apis/urlfetch.rb:31:in `require'

        from C:/jruby-1.3.1/bin/../lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
        from config.ru:3:in `generate_xml'

Are there specific versions of java or jruby that you are using? Did you have to set some environment variables? The fact that appengine-rack works but appengine-apis crashes makes me think my environment is set up properly.

Comment by jbarsook, Aug 21, 2009

When I run "dev_appserver.rb ." I receive the following error (see bottom for my system configuration):

JRuby limited openssl loaded. gem install jruby-openssl for full support. http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL => Booting DevAppServer? => Press Ctrl-C to shutdown server => Installing JRuby => Retrieving jruby-rack => Installing appengine-sdk => Generating configuration files 2009-08-21 18:25:40.472 java38102:80f? CocoaComponent compatibility mode?: Enabled 2009-08-21 18:25:40.473 java38102:80f? CocoaComponent compatibility mode?: Setting timeout for SWT to 0.100000 Aug 22, 2009 1:26:57 AM com.google.appengine.tools.development.ApiProxyLocalImpl? log SEVERE: 1250904417044000? javax.servlet.ServletContext? log: Warning: error application could not be initialized org.jruby.rack.RackInitializationException?: Operation timed out

at org.jruby.rack.DefaultRackApplicationFactory?.newRuntime(DefaultRackApplicationFactory?.java:82) at org.jruby.rack.DefaultRackApplicationFactory?.createApplication(DefaultRackApplicationFactory?.java:146) at org.jruby.rack.DefaultRackApplicationFactory?.newErrorApplication(DefaultRackApplicationFactory?.java:96) at org.jruby.rack.DefaultRackApplicationFactory?.init(DefaultRackApplicationFactory?.java:36) at org.jruby.rack.SharedRackApplicationFactory?.init(SharedRackApplicationFactory?.java:25) at org.jruby.rack.RackServletContextListener?.contextInitialized(RackServletContextListener?.java:39) at org.mortbay.jetty.handler.ContextHandler?.startContext(ContextHandler?.java:530) at org.mortbay.jetty.servlet.Context.startContext(Context.java:135) at org.mortbay.jetty.webapp.WebAppContext?.startContext(WebAppContext?.java:1218) at org.mortbay.jetty.handler.ContextHandler?.doStart(ContextHandler?.java:500) at org.mortbay.jetty.webapp.WebAppContext?.doStart(WebAppContext?.java:448) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at org.mortbay.jetty.handler.HandlerWrapper?.doStart(HandlerWrapper?.java:117) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at org.mortbay.jetty.handler.HandlerWrapper?.doStart(HandlerWrapper?.java:117) at org.mortbay.jetty.Server.doStart(Server.java:217) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at com.google.appengine.tools.development.JettyContainerService?.startContainer(JettyContainerService?.java:152) at com.google.appengine.tools.development.AbstractContainerService?.startup(AbstractContainerService?.java:116) at com.google.appengine.tools.development.DevAppServerImpl?.start(DevAppServerImpl?.java:218) at com.google.appengine.tools.development.DevAppServerMain?$StartAction?.apply(DevAppServerMain?.java:162) at com.google.appengine.tools.util.Parser$ParseResult?.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain?.<init>(DevAppServerMain?.java:113) at com.google.appengine.tools.development.DevAppServerMain?.main(DevAppServerMain?.java:89)

Caused by: org.jruby.exceptions.RaiseException?: Operation timed out

at (unknown).initialize(:1) at (unknown).(unknown)(:1)

Aug 22, 2009 1:28:12 AM com.google.appengine.tools.development.ApiProxyLocalImpl? log SEVERE: 1250904492047000? javax.servlet.ServletContext? log: unable to create shared application instance org.jruby.rack.RackInitializationException?: Operation timed out

at org.jruby.rack.DefaultRackApplicationFactory?.newRuntime(DefaultRackApplicationFactory?.java:82) at org.jruby.rack.DefaultRackApplicationFactory?.createApplication(DefaultRackApplicationFactory?.java:146) at org.jruby.rack.DefaultRackApplicationFactory?.newApplication(DefaultRackApplicationFactory?.java:41) at org.jruby.rack.DefaultRackApplicationFactory?.getApplication(DefaultRackApplicationFactory?.java:49) at org.jruby.rack.SharedRackApplicationFactory?.init(SharedRackApplicationFactory?.java:26) at org.jruby.rack.RackServletContextListener?.contextInitialized(RackServletContextListener?.java:39) at org.mortbay.jetty.handler.ContextHandler?.startContext(ContextHandler?.java:530) at org.mortbay.jetty.servlet.Context.startContext(Context.java:135) at org.mortbay.jetty.webapp.WebAppContext?.startContext(WebAppContext?.java:1218) at org.mortbay.jetty.handler.ContextHandler?.doStart(ContextHandler?.java:500) at org.mortbay.jetty.webapp.WebAppContext?.doStart(WebAppContext?.java:448) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at org.mortbay.jetty.handler.HandlerWrapper?.doStart(HandlerWrapper?.java:117) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at org.mortbay.jetty.handler.HandlerWrapper?.doStart(HandlerWrapper?.java:117) at org.mortbay.jetty.Server.doStart(Server.java:217) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at com.google.appengine.tools.development.JettyContainerService?.startContainer(JettyContainerService?.java:152) at com.google.appengine.tools.development.AbstractContainerService?.startup(AbstractContainerService?.java:116) at com.google.appengine.tools.development.DevAppServerImpl?.start(DevAppServerImpl?.java:218) at com.google.appengine.tools.development.DevAppServerMain?$StartAction?.apply(DevAppServerMain?.java:162) at com.google.appengine.tools.util.Parser$ParseResult?.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain?.<init>(DevAppServerMain?.java:113) at com.google.appengine.tools.development.DevAppServerMain?.main(DevAppServerMain?.java:89)

Caused by: org.jruby.exceptions.RaiseException?: Operation timed out

at (unknown).initialize(:1) at (unknown).(unknown)(:1)

Aug 22, 2009 1:28:12 AM com.google.appengine.tools.development.ApiProxyLocalImpl? log SEVERE: 1250904492047000? javax.servlet.ServletContext? log: Error: application initialization failed org.jruby.rack.RackInitializationException?: unable to create shared application instance

at org.jruby.rack.SharedRackApplicationFactory?.init(SharedRackApplicationFactory?.java:38) at org.jruby.rack.RackServletContextListener?.contextInitialized(RackServletContextListener?.java:39) at org.mortbay.jetty.handler.ContextHandler?.startContext(ContextHandler?.java:530) at org.mortbay.jetty.servlet.Context.startContext(Context.java:135) at org.mortbay.jetty.webapp.WebAppContext?.startContext(WebAppContext?.java:1218) at org.mortbay.jetty.handler.ContextHandler?.doStart(ContextHandler?.java:500) at org.mortbay.jetty.webapp.WebAppContext?.doStart(WebAppContext?.java:448) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at org.mortbay.jetty.handler.HandlerWrapper?.doStart(HandlerWrapper?.java:117) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at org.mortbay.jetty.handler.HandlerWrapper?.doStart(HandlerWrapper?.java:117) at org.mortbay.jetty.Server.doStart(Server.java:217) at org.mortbay.component.AbstractLifeCycle?.start(AbstractLifeCycle?.java:40) at com.google.appengine.tools.development.JettyContainerService?.startContainer(JettyContainerService?.java:152) at com.google.appengine.tools.development.AbstractContainerService?.startup(AbstractContainerService?.java:116) at com.google.appengine.tools.development.DevAppServerImpl?.start(DevAppServerImpl?.java:218) at com.google.appengine.tools.development.DevAppServerMain?$StartAction?.apply(DevAppServerMain?.java:162) at com.google.appengine.tools.util.Parser$ParseResult?.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain?.<init>(DevAppServerMain?.java:113) at com.google.appengine.tools.development.DevAppServerMain?.main(DevAppServerMain?.java:89)
Caused by: org.jruby.rack.RackInitializationException?: Operation timed out

at org.jruby.rack.DefaultRackApplicationFactory?.newRuntime(DefaultRackApplicationFactory?.java:82) at org.jruby.rack.DefaultRackApplicationFactory?.createApplication(DefaultRackApplicationFactory?.java:146) at org.jruby.rack.DefaultRackApplicationFactory?.newApplication(DefaultRackApplicationFactory?.java:41) at org.jruby.rack.DefaultRackApplicationFactory?.getApplication(DefaultRackApplicationFactory?.java:49) at org.jruby.rack.SharedRackApplicationFactory?.init(SharedRackApplicationFactory?.java:26) ... 19 more

Caused by: org.jruby.exceptions.RaiseException?: Operation timed out

at (unknown).initialize(:1) at (unknown).(unknown)(:1)

The server is running at http://localhost:8080/


MY SETUP: - Mac OS X 10.5.8 - jruby 1.3.1 (ruby 1.8.6p287) (2009-08-09 6586) (Java HotSpot?(TM) Client VM 1.5.0_19) i386-java? - GEMS: actionmailer (2.3.3) actionpack (2.3.3) activerecord (2.3.3) activeresource (2.3.3) activesupport (2.3.3) addressable (2.1.0) appengine-apis (0.0.8) appengine-jruby-jars (0.0.2) appengine-rack (0.0.2) appengine-sdk (1.2.2) appengine-tools (0.0.2) extlib (0.9.13) google-appengine (0.0.2) rack (1.0.0) rails (2.3.3) rake (0.8.7) rspec (1.2.6) sources (0.0.1)

Any ideas about why this isn't working? On my other Mac with an identical setup, it works fine.

Comment by m...@quantificate.com, Aug 23, 2009

For anybody who is having problems with the Java SDK classes not being found (e.g. "cannot load Java class com.google.appengine.api.urlfetch.FetchOptions? (NameError?)", I worked around it by:

Adding $APPENGINE_HOME/lib/impl to the RUBYLIBS environmental variable Requiring the appengine jars in my sinatra app.rb, thus:

require 'appengine-api.jar' require 'appengine-api-stubs.jar' require 'appengine-local-runtime.jar'

(I suspect those three lines will need commenting before deploying...)

The first time I launched the app after that it failed, but a second time and it worked fine.

I also recommend anybody using Merb or Sinatra take a look at jruby-enginize, which generates GAE apps and provides rake tasks for bundling, running, deploying etc: http://github.com/ulbrich/jruby-enginize/tree/master (I'm not a contributor, just a happy user)

Comment by m...@quantificate.com, Aug 23, 2009

PS. Obviously APPENGINE_HOME is set to the base AppEngine? Java SDK directory...

Comment by ribrdb, Aug 24, 2009

If you're having trouble please use the appengine-jruby mailing list. It's very hard to keep track of the different conversations going on in these comments.

Comment by michal.hantl, Sep 02, 2009

I have deployed my little app to appengine using jruby-appengine. Everything works as expected. Thank you developers!

Comment by crouchendgas, Nov 07, 2009

i can run dev_appserver.rb as root on ubuntu linux but not as a user i seem to be getting permission errors. can anybody help ?

Comment by marcos.neves, Nov 18 (2 days ago)

I am trying to create a sample with ramaze, but it look likes that this kind of file iteration does not work inside gems.jar

Find.find(File.expand_path('../snippets', FILE)) do |file|

require(file) if file =~ /\.rb$/ && File.file?(file)
end

founded in ramaze-2009.10/lib/ramaze/snippets.rb

Comment by marcos.neves, Nov 18 (2 days ago)

How can I use a gem outside a jar?


Sign in to add a comment