My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
SinatraReloaded  
Getting Started guide for Sinatra with focus on development environment
Featured
Updated Feb 7, 2010 by lazy.gop...@gmail.com

Introduction

This guide is based on GettingStarted guide, but extends it with templating changed to HAML. The Rack::Reloader is used for reloading development environment.

Local installation

It's important to understand that development environment for the appengine and the Jruby contain 3 different places of ruby gems:

  • system ruby gems. These gems come with your MRI Ruby. You should definitely use MRI ruby. Current appengine-jruby doesn't work with jruby. Gems here contain minimum for development environment.
  • application gems. This is the .gems folder in your application directory. These gems installed by bundler and used for caching only.
  • deployment gems. This is copy of the application gems packed into the gems.jar file in ./WEB-INF/lib directory. The appengine has limitation on amount of files but jruby can read gems from jar archive. So, for deployment, application gems are packed to gems.jar.

System ruby gems installation

First, make sure that you have the latest version of gem installed

$ gem --version
1.3.5
$ # If you have the older version perform upgrade
$ gem update --system
$ # Install the required system gems
$ gem install --no-rdoc --no-ri google-appengine

Application gems installation

Create the folder for application. In this guide it's assumed to be ~/guestbook/.

$ mkdir guestbook
$ cd guestbook

In order to manage gems one need to create the Gemfile control file. Ours will be pretty simple.

$ cat >Gemfile <<EOF

disable_system_gems
disable_rubygems
bundle_path ".gems/bundler_gems"

gem "sinatra"
gem "dm-core"
gem "dm-appengine"
gem "haml"

EOF

Creating application

First let's create the config.ru, which will configure application and reloading for development environment. The simple use Rack::Reloader will not work as we need to reload the Sinatra framework.

$ cat >config.ru <<EOF 
require 'appengine-rack'
require 'guestbook'

AppEngine::Rack.configure_app(:application => "guestbook", :version => 1)

configure :development do
  class Sinatra::Reloader < ::Rack::Reloader
    def safe_load(file, mtime, stderr)
      if File.expand_path(file) == File.expand_path(::Sinatra::Application.app_file)
        ::Sinatra::Application.reset!
        stderr.puts "#{self.class}: reseting routes"
      end
      super
    end
  end
  use Sinatra::Reloader
end

run Sinatra::Application
EOF

The reloader example, above, assumes that application is Sinatra traditional style application and all routes defined in the 'guestbook.rb' file, or main file of the application.

If application has a separate file for routes, for example 'route.rb', then ::Sinatra::Application.app_file should be replaced with './route.rb' or similar. What is meant here is that you need to do .reset! only in case when file with routes changes. If you routes scattered in different files you need to write more complex reloading strategy.

If you are using 'sinatra/base' instead of the traditional Sinatra application, you, probably, already found out, that you should take care about everything yourself. And the reloader is no exception. Everywhere, where ::Sinatra::Application mentioned, you need to replace it with your class. Assume following example:

require 'sinatra/base'
class Simple < Sinatra::Base
  get '/' do
     'Hello World!'
  end
end

then your reloader should do Simple.reset! for file with routes. And, of course, you need to change run Sinatra::Application to run Simple.new.

Now, let's get back and put the application itself

$ cat >guestbook.rb <<EOF 
require 'sinatra'
require 'dm-core'
require 'haml'

# 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

# Set Haml output format and enable escapes
set :haml, {:format => :html5 , :escape_html => true }

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

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

Let's add some templates as well

$ mkdir views

First, the above-mentioned index.haml

$ cat >views/index.haml <<EOF
%h2 Messages
- for shout in @shouts
  %p<
    Someone wrote,
    %q= shout.message

%form{:method => :post}  
  %textarea{:name => :message}  
  %br/
  %input{:type => :submit, :method => :Shout}
EOF

And the layout for the application

$ cat >views/layout.haml <<EOF
!!!
%html
  %head
    %title Guestbook
  %body
    != yield
EOF

Running servers

Now, finally we are ready to run the development with Sinatra reloading.

$ dev_appserver.rb .

The Rack::Reloader uses mtime on your system, so if the reloader is not doing its job try touch guestbook.rb.

Enjoy!

all question and improvements are welcome in the google group

Comment by richard....@gmail.com, Nov 3, 2009

I tried to use your reloader but it fails because I have a diferent file for all my models. When I save any file in my application, the application starts sending a not found in every in route... any advice?

Comment by lazy.gop...@gmail.com, Nov 7, 2009

Richard, how do you include the code in your application? Reloader works only with "require" and does not with "load". Do you see in the log the "reloaded" message ?

Comment by khel...@gmail.com, Nov 9, 2009

when running appcfg.rb bundle . i get:

/usr/lib/ruby/site_ruby/1.8/rubygems.rb:280:in `activate': can't activate bundler (= 0.6.0, runtime) for ["appengine-tools-0.0.5"], already activated bundler-0.7.0 for (Gem::LoadError?)

from /usr/lib/ruby/site_ruby/1.8/rubygems.rb:296:in `activate' from /usr/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `each' from /usr/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `activate' from /usr/lib/ruby/site_ruby/1.8/rubygems.rb:68:in `gem' from /usr/bin/appcfg.rb:18

Trying to overcome it usging JRuby:

jruby -S appcfg.rb bundle .

i get nothing and gems.jar is not even generated....

Comment by lazy.gop...@gmail.com, Nov 10, 2009

this is bug in current version - see  bug 36 . Uninstall bundler v 0.7.0 with your MRI ruby and install v 0.6.0

gem uninstall bundler

gem install bundler -v 0.6.0

or, alternatively, don't install bundler manually as mentioned above, then correct version will be installed with google-appengine gem.

Comment by tomgu...@gmail.com, Nov 18, 2009

I'm getting this error on Ubuntu. I think it's a user permission issue with the library. All my other ruby gems work fine, so it may be an issue with appengine-jruby and Ubuntu.

/usr/lib/ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require': no such file to load -- appengine-tools/dev_appserver (LoadError?)

from /usr/lib/ruby/1.8/rubygems/custom_require.rb:36:in `require' from /var/lib/gems/1.8/gems/appengine-tools-0.0.5/bin/dev_appserver.rb:17 from /var/lib/gems/1.8/bin/dev_appserver.rb:19:in `load' from /var/lib/gems/1.8/bin/dev_appserver.rb:19

Comment by pftg.sof, Nov 19, 2009

Also, bundler do not install gems for java platform. May be better install gems through old solutions while builder do not updated.

Comment by jSlim...@gmail.com, Dec 21, 2009

In the last section, under "Install deployment gems and create local structure", "appcfg.rb gem bundle" is deprecated. The new syntax is displayed, however, when that is used a classpath exception is thrown. This happened on Cygwin.

See: http://groups.google.com/group/appengine-jruby/browse_thread/thread/bae51f86fc5b5063

Comment by eiffel...@gmail.com, May 10, 2010

got error org.jruby.rack.RackInitializationException?: No such file or directory - /Users/eiffel/web/guestbook/file:/Users/eiffel/web/guestbook/WEB-INF/lib/gems.jar!/bundler_gems/jruby/1.8/gems/haml-3.0.0/VERSION

Comment by rsaccon, May 15, 2010

getting the same error

Comment by willy.na...@gmail.com, May 15, 2010

eiffelqiu & rsaccon : downgrade to haml 2.2.24 should be fine.. pls use mailing list as it's more suitable for questions, plus tons of ppl there with answers.

Comment by vty...@gmail.com, Jul 1, 2010

Based on this guide, i have succesfully deployed my first innate-based app in google appengine. As you should know innate is the core of the ramaze web framework. I wrote a short guide on http://innate-gae.appspot.com including the appropriate Gemfile and config.ru . Thnx.

Comment by isap...@gmail.com, Apr 17, 2011

failure #1

Caused by: org.jruby.exceptions.RaiseException???: (NoMethodError???) undefined method `configure_app' for AppEngine???::Rack:Module

Fix by commenting out:

# AppEngine???::Rack.configure_app(:application => "guestbook", :version => 1)

http://groups.google.com/group/appengine-jruby/browse_thread/thread/2a512ce3294892db

failure #2:

#<NameError??: uninitialized constant DataMapper??::Adapters::AppEngineAdapter??::Extlib>

http://code.google.com/p/appengine-jruby/issues/detail?id=93

fix by downgrading dm-core to 1.0.2

still getting this error on startup: /usr/local/lib/ruby/gems/1.8/gems/appengine-tools-0.0.17/lib/appengine-tools/dev_appserver.rb:86:in `exec': Operation not supported - java (Errno::E045)

from /usr/local/lib/ruby/gems/1.8/gems/appengine-tools-0.0.17/lib/appengine-tools/dev_appserver.rb:86:in `start_java'

but app seems to work.

Comment by mjt...@gmail.com, Jul 13, 2011

Many thanks for the hints above, working a treat now!

BTW, I wouldn't suggest doing this:

$ # If you have the older version perform upgrade $ gem update --system

It turns out that you need to be on rubygems <= 1.3.7 rather than the latest (1.8.5 as of the time of writing). Also worth noting you need to be using a ruby 1.8.7 interpreter, not a 1.9.1+ interpreter.

Comment by a.c.hansonjr@gmail.com, Jul 15, 2011

Downgrading to dm-core 1.0.2 worked for me as well. To make this easy I just modified in Gemfile where dm-core is a dependency to: gem "dm-core", "= 1.0.2"


Sign in to add a comment
Powered by Google Project Hosting