<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>IONCANNON &#187; rack</title>
	<atom:link href="http://www.ioncannon.net/tag/rack/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ioncannon.net</link>
	<description>Thoughts on Software Development and Engineering</description>
	<lastBuildDate>Tue, 03 Jan 2012 13:59:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
	<atom:link rel='hub' href='http://www.ioncannon.net/?pushpress=hub'/>
		<item>
		<title>Getting Started with JRuby Webapps using Rack and Sinatra</title>
		<link>http://www.ioncannon.net/programming/1325/getting-started-with-jruby-webapps-using-rack-and-sinatra/</link>
		<comments>http://www.ioncannon.net/programming/1325/getting-started-with-jruby-webapps-using-rack-and-sinatra/#comments</comments>
		<pubDate>Thu, 07 Oct 2010 11:17:16 +0000</pubDate>
		<dc:creator>carson</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[jruby]]></category>
		<category><![CDATA[mizuno]]></category>
		<category><![CDATA[rack]]></category>
		<category><![CDATA[sinatra]]></category>

		<guid isPermaLink="false">http://www.ioncannon.net/?p=1325</guid>
		<description><![CDATA[Going to JRubyConf inspired me enough to expand my knowledge of JRuby. This is a quick guide for anyone looking to see what can be done with JRuby and Sinatra. Of course the first step is to install the Java JDK. Download, install and then set it up in your path. I&#039;m using JDK 6 [...]]]></description>
			<content:encoded><![CDATA[<p>Going to <a href="http://jrubyconf.com/">JRubyConf</a> inspired me enough to expand my knowledge of <a href="http://jruby.org/">JRuby</a>. This is a quick guide for anyone looking to see what can be done with JRuby and Sinatra.</p>
<p>Of course the first step is to install the <a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">Java JDK</a>. Download, install and then set it up in your path. I&#039;m using JDK 6 update 21 on Linux for this post in case it matters.</p>
<p>There are a couple ways to install JRuby after you have Java installed. The hard way is to <a href="http://www.jruby.org/download">download JRuby</a> and install it by hand. The easy way is to use <a href="http://rvm.beginrescueend.com/">Ruby Version Manager</a> to install it. Using RVM will let you switch between Ruby versions as well as giving you a simple command to install JRuby:</p>
<pre class="brush: plain; title: ; notranslate">
rvm install jruby
rvm use jruby
</pre>
<p><span id="more-1325"></span></p>
<p>At this point you should be able to run a test JRuby application and install gems in the JRuby environment. The next step is to install a few gems. Those gems are <a href="http://github.com/matadon/mizuno">mizuno</a>, <a href="http://rack.rubyforge.org/">rack</a> and <a href="http://www.sinatrarb.com/">sinatra</a>:</p>
<pre class="brush: plain; title: ; notranslate">
gem install mizuno rack sinatra
</pre>
<p>Of these three packages the one that you may not have heard about is mizuno. Mizuno runs a Java based web container called Jetty and will allow you to easily run rack based JRuby apps easily. Beyond the ease of running Rack apps mizuno is also very fast but for this post the main thing is that it gives you a very easy way to get the sinatra application up and running without a lot of work.</p>
<p>You now have all the basics installed and it is time to create a simple sinatra app. Start by creating a file named myapp.rb with the follwing in it:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'sinatra/base'

class MyApp &lt; Sinatra::Base
  get '/' do
    'Hello world!'
  end
end
</pre>
<p>This is a very simple sinatra application that will display &#034;Hello world!&#034; whenever you get the root URL. Check out the <a href="http://www.sinatrarb.com/intro.html">sinatra intro</a> for more information about sinatra if you aren&#039;t already familiar with it.</p>
<p>Next you will need to create a rack configuration file named config.ru in the same directory as your myapp.rb file:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'rubygems'
require 'myapp'

MyApp.run! :host =&gt; 'localhost', :port =&gt; 8080
</pre>
<p>The above configuration tells rack to run the simple MyApp application on localhost:8080.</p>
<p>Now you are ready to start the application with mizuno. In the same directory as the config.ru and myapp.rb file run the following command:</p>
<pre class="brush: plain; title: ; notranslate">
mizuno
</pre>
<p>Something like the following should be displayed on the console after running the command:</p>
<pre class="brush: plain; title: ; notranslate">
== Sinatra/1.0 has taken the stage on 8080 for development with backup from WEBrick
[2010-10-04 21:04:06] INFO  WEBrick 1.3.1
[2010-10-04 21:04:06] INFO  ruby 1.8.7 (2010-09-28) 1
[2010-10-04 21:04:06] INFO  WEBrick::HTTPServer#start: pid=26276 port=8080
</pre>
<p>Now if you connect to localhost:8080 with a web browser you will see &#034;Hello world!&#034; To stop the mizuno server just hit ctrl-c. I found that the mizuno didn&#039;t stop completely after ctrl-c so I ended up having to kill it but that may not happen on every system.</p>
<p>At this point you are able to make simple applications with sinatra and JRuby but you won&#039;t want to stop there. Your next step will be to use a database. For database access I decided to use <a href="http://datamapper.org/">DataMapper</a> on top of SQLite. If you aren&#039;t familiar with DataMapper check out the <a href="http://datamapper.org/getting-started">DataMapper getting started guide</a>. Use the following command to get the DataMapper gems installed with SQLite support:</p>
<pre class="brush: plain; title: ; notranslate">
gem install dm-core dm-migrations dm-sqlite-adapter
</pre>
<p>The following code adds a DataEntry model and two routes to the original simple application. The &#034;get /data&#034; route will display all the current DataEntry values in the database and give you a form to enter more. The &#034;post /data&#034; route will take a new entry to add to the database:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'sinatra/base'
require 'dm-core'
require 'dm-migrations'

class DataEntry
  include DataMapper::Resource

  property :id, Serial
  property :entry, String
end

class MyApp &lt; Sinatra::Base
  configure do
    DataMapper::Logger.new($stdout, :debug)
    DataMapper.setup(:default, 'sqlite:///tmp/survey.db')
    DataMapper.auto_upgrade!
  end

  get '/' do
    'Hello world!'
  end

  get '/data' do
    display_value = '&lt;ol&gt;'
    DataEntry.all.each do |data|
      display_value += '&lt;li&gt;' + data.entry + '&lt;/li&gt;'
    end
    display_value += '&lt;/ol&gt;'
    display_value += '&lt;form action=&quot;/data&quot; method=&quot;POST&quot;&gt;'
    display_value += 'Entry: &lt;input name=&quot;entry&quot; type=&quot;text&quot;/&gt;&lt;br/&gt;'
    display_value += '&lt;input type=&quot;submit&quot;/&gt;'
    display_value += '&lt;/form&gt;'
  end

  post '/data' do
    @entry = DataEntry.create(:entry =&gt; params[:entry])
    'Entry created&lt;br/&gt; &lt;a href=&quot;/data&quot;&gt;Enter more&lt;/a&gt;'
  end
end
</pre>
<p>I&#039;ve put the entire contents of the application into one file for simplicity. With something more complex you would want to split the file up as well as use templates instead of building strings of output.</p>
<p>Adding templates is easy as well. The sinatra reference documentation has examples of a number of different templating engines but I&#039;m going to use <a href="http://haml-lang.com/">haml templates</a> for one final example. Use the following command to install the haml gem:</p>
<pre class="brush: plain; title: ; notranslate">
gem install haml
</pre>
<p>The following code does the same thing as the last version but uses named templates, check out the <a href="http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html">haml reference</a> for details:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'sinatra/base'
require 'dm-core'
require 'dm-migrations'
require 'haml'

class DataEntry
  include DataMapper::Resource

  property :id, Serial
  property :entry, String
end

class MyApp &lt; Sinatra::Base
  configure do
    DataMapper::Logger.new($stdout, :debug)
    DataMapper.setup(:default, 'sqlite:///tmp/survey.db')
    DataMapper.auto_upgrade!
  end

  get '/' do
    haml :index
  end

  get '/data' do
    haml :data_entry, :locals =&gt; { :data =&gt; DataEntry.all }
  end

  post '/data' do
    @entry = DataEntry.create(:entry =&gt; params[:entry])
    haml :data_created
  end

  template :layout do
    &quot;%html\n  =yield\n&quot;
  end

  template :index do
    '%h2 Hello World!'
  end

  template :data_entry do
    &quot;%ol\n&quot; +
    &quot;  - data.each do |entry|\n&quot; +
    &quot;    %li= entry.entry\n&quot; +
    &quot;%form{:action =&gt; '', :method =&gt; 'post'}\n&quot; +
    &quot;  Entry:\n&quot;+
    &quot;  %input{:type =&gt; 'text', :name =&gt; 'entry'}\n&quot;+
    &quot;  %input{:type =&gt; 'submit', :value =&gt; 'Create'}&quot;
  end

  template :data_created do
    &quot;%div\n&quot; +
    &quot;  Entry created\n&quot; +
    &quot;%a(href='/data') Enter more&quot;
  end
end
</pre>
<p>Again, I&#039;ve included everything in one file for simplicity but you would want to split this up. Note that I&#039;m building the haml template structure as strings here and that is why there are \ns and spaces in each string. Creating separate files for each template would be the way to go in any complex application.</p>
<p>I had already been thinking about using JRuby before the conference as a way to show that Java on a TTYLinux box can be widely useful. One of the main drawbacks of running TTYLinux is that you have to build everything by hand and that can get complicated. With Java you don&#039;t have to worry about that complexity since it is all just bytecode and the static JVM binary works just fine on TTYLinux out of the box. I think <a href="http://www.ioncannon.net/system-administration/1310/minimal_ec2_linux_install_using_ttylinux/">TTYLinux on EC2</a> and Java could be a powerful solution.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioncannon.net/programming/1325/getting-started-with-jruby-webapps-using-rack-and-sinatra/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Heroku Tips for the Cheap</title>
		<link>http://www.ioncannon.net/programming/842/heroku-tips-for-the-cheap/</link>
		<comments>http://www.ioncannon.net/programming/842/heroku-tips-for-the-cheap/#comments</comments>
		<pubDate>Sun, 20 Dec 2009 10:50:14 +0000</pubDate>
		<dc:creator>carson</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[rack]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://www.ioncannon.net/?p=842</guid>
		<description><![CDATA[I&#039;ve been playing around with the Ruby/Rails cloud provider Heroku a little bit lately just to try it out. It is somewhat like Google App Engine or Microsoft Azure in the way it works since you bundle your application and push it out to the Heroku cloud for deployment. It is very easy to get [...]]]></description>
			<content:encoded><![CDATA[<p>I&#039;ve been playing around with the Ruby/Rails cloud provider <a href="http://www.heroku.com">Heroku</a> a little bit lately just to try it out. It is somewhat like Google App Engine or Microsoft Azure in the way it works since you bundle your application and push it out to the Heroku cloud for deployment. It is very easy to get things going but I ran into a few interesting items that I figured I would share. </p>
<p><span id="more-842"></span></p>
<p>Some of the following grew out of the requirement that you verify for a lot of the Heroku addons and verification requires a credit card. For some of these tips there are easier paths if you don&#039;t mind paying a little extra or just verifying your account.</p>
<ul>
<li><a href="#heroku-config">Configuration</a></li>
<li><a href="#heroku-cname">Set up a custom domain name</a></li>
<li><a href="#heroku-cron">Poor man&#039;s cron</a></li>
<li><a href="#heroku-gmail">Sending mail with GMail</a></li>
<li><a href="#heroku-logs">Keeping your logs</a></li>
<li><a href="#heroku-rack">Rack works too</a></li>
<li><a href="#heroku-compiled-gems">Compiled gems</a></li>
<li><a href="#heroku-dynos">Understanding dynos</a></li>
</ul>
<p><a name="heroku-config"><b>Configuration</b></a></p>
<p>For configuration <a href="http://docs.heroku.com/config-vars#local-setup">Heroku has a way</a> but for some reason it didn&#039;t seem like the best or easiest way to do things. I started off setting up a configuration file as described in this <a href="http://railscasts.com/episodes/85-yaml-configuration-file">railscast on using yaml configuration files</a>. I took a while to dig a little more and found something similar but even <a href="http://almosteffortless.com/2009/06/25/config-vars-and-heroku/">better way of doing configuration with Heroku</a>.</p>
<p><a name="heroku-cname"><b>Set up a custom domain name</b></a></p>
<p>To make a more professional looking app you probably want to have a non-Heroku base domain name. They make it very easy to set that up using a <a href="http://docs.heroku.com/custom-domains#cname-setup">CNAME DNS entry</a>.</p>
<p><a name="heroku-cron"><b>Poor man&#039;s cron</b></a></p>
<p>One of the things I ran into pretty quickly was the need to run a task once every minute. Heroku offers both <a href="http://docs.heroku.com/cron">cron</a> and <a href="http://docs.heroku.com/delayed-job">delayed job</a>. The cron jobs offered are a little limited since the finest grained execution for cron is once an hour. I believe delayed jobs could be made to run every minute but the next issue with both cron and delayed job on Heroku is that they are addons that require verification. </p>
<p>The solution for me was to create a poor man&#039;s cron. I added a controller that would execute the task and then ran wget to hit the controller from an external server. This isn&#039;t a great solution but for testing the service it worked fine. The main note on doing this is to keep in mind that you will tie up a dyno for the length of the request, see <a href="#heroku-dynos">Understanding dynos</a> for more.</p>
<p><a name="heroku-gmail"><b>Sending mail with GMail</b></a></p>
<p>If you want to send email you have a number of different options on Heroku. First off it is important to note that Heroku doesn&#039;t support sending email from their systems directly but instead they support outgoing <a href="http://docs.heroku.com/smtp">SMTP</a>. Sending mail with the <a href="http://docs.heroku.com/sendgrid">Sendgrid addon</a> is probably the most flexible option but the <a href="http://docs.heroku.com/gmail-smtp">GMail SMTP</a> option is the least costly. The GMail option gives you 500 emails a day and that was plenty for my use. </p>
<p>Even though there is an addon for the GMail option you don&#039;t actually need to use it. Instead install the <a href="http://github.com/collectiveidea/action_mailer_optional_tls">action mailer optional TLS plugin</a>. Follow the readme to get it installed and configured. Then you put something like the following into your production.rb file:</p>
<pre class="brush: plain; title: ; notranslate">
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.raise_delivery_errors = true
  ActionMailer::Base.smtp_settings = {
    :tls            =&gt; true,
    :address        =&gt; 'smtp.gmail.com',
    :port           =&gt; 587,
    :domain         =&gt; 'example.come',
    :authentication =&gt; :plain,
    :user_name      =&gt; 'support@example.com',
    :password       =&gt; 'password'
  }
</pre>
<p><br/></p>
<p><a name="heroku-logs"><b>Keeping your logs</b></a></p>
<p>One downside to Heroku is that they only retain a small portion of your logs. They indicate in their docs that they only retain <a href="http://docs.heroku.com/logs-exceptions">100 lines of logs</a>. So if you want to track your log output you will need to store them outside of the service. They give two suggestions in the docs for logging but there are other ways to do something similar on your own.</p>
<p>The solution I found that seems like the easiest is to use <a href="http://blog.philburrows.com/articles/2009/09/28/rails-logging-with-mongodb/">MongoDB to log</a> since it is <a href="http://blog.mongodb.org/post/172254834/mongodb-is-fantastic-for-logging">&#034;fantastic for logging&#034;</a>. You will need to have a <a href="http://www.mongodb.org/">MongoDB</a> server available first. If you don&#039;t want to <a href="http://www.engineyard.com/blog/2009/mongodb-a-light-in-the-darkness-key-value-stores-part-5/">install MongoDB on your own external server</a> you can try the new <a href="http://mongohq.com/">MongoDB hosted solution</a>.</p>
<p>Once you have the MongoDB server ready you will need to add the MongoDB gem to your .gems file:</p>
<pre class="brush: plain; title: ; notranslate">
mongodb-mongo --source gems.github.com
</pre>
<p>Then you will want to install the <a href="http://github.com/peburrows/mongo_db_logger">mongo db logger</a> plugin in your rails project. Just follow the instructions they give on the project page to get it installed. </p>
<p>Your app/controllers/application_controller.rb will look something like this:</p>
<pre class="brush: ruby; title: ; notranslate">
class ApplicationController &lt; ActionController::Base
  include MongoDBLogging

  helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
end
</pre>
<p>After you get the plugin installed you will have to hard code the MongoDB information into the plugin. This could probably be fixed and pulled out of a configuration file but it won&#039;t work the way it is set up out of the box. Edit the file vendor/plugins/mongo_db_logger/lib/mongo_logger.rb and change the db_configuration to match your setup. It should be something like this:</p>
<pre class="brush: plain; title: ; notranslate">
  db_configuration = {
    'host'    =&gt; 'my.mongohost.com',
    'port'    =&gt; 56700,
    'database'    =&gt; 'testapp',
    'capsize' =&gt; default_capsize}
</pre>
<p>Now you should be able to deploy to Heroku and see your logs show up in your MongoDB database.</p>
<p>A couple very important things to note are that this logging won&#039;t catch exceptions that happen above the application itself and if your MongoDB server goes down your app may hang trying to connect to it.</p>
<p><a name="heroku-rack"><b>Rack works too</b></a></p>
<p>You aren&#039;t limited to just Ruby on Rails with Heroku, <a href="http://docs.heroku.com/rack">rack works</a> as well. That opens the door for other frameworks like <a href="http://www.sinatrarb.com/">Sinatra</a>, <a href="http://merbivore.com/">Merb</a> and <a href="http://camping.rubyforge.org/files/README.html">Camping</a> on Heroku. It is also possible that more in depth logging could be done using <a href="http://clogger.rubyforge.org/">clogger</a> or even <a href="http://www.rackamole.com/">rack a mole</a>.</p>
<p>Here is an example Camping application:</p>
<p>The .gems file:</p>
<pre class="brush: plain; title: ; notranslate">
camping
</pre>
<p>The config.ru file:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'hello'
run Rack::Adapter::Camping.new(Hello)
</pre>
<p>The hello.rb file:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'camping'

Camping.goes :Hello

module Hello::Controllers
  class Index &lt; R '/'
     def get
        render :hello
     end
  end
end

module Hello::Views
  def hello
     p  &quot;Hello World!&quot;
  end
end
</pre>
<p><br/></p>
<p><a name="heroku-compiled-gems"><b>Compiled gems</b></a></p>
<p>Heroku also lets you use gems that need to be compiled before they are installed. You can see this if you try to use something like <a href="http://github.com/ice799/memprof">memprof</a> however you will also notice that in the memprof case it won&#039;t actually work because there are missing libraries. So using gems that require libraries may be hit or miss. </p>
<p>If you are lucky you may find that the gem is already part of Heroku like RMagick is. Here is a little example of using Heroku and the RMagick gem to produce an image using Camping:</p>
<p>The .gems file:</p>
<pre class="brush: plain; title: ; notranslate">
camping
rmagick
</pre>
<p>The config.ru file:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'hello'
run Rack::Adapter::Camping.new(Hello)
</pre>
<p>The hello.rb file:</p>
<pre class="brush: ruby; title: ; notranslate">
require 'camping'
require 'RMagick'

Camping.goes :Hello

module Hello::Controllers
  class Index &lt; R '/'
     def get
       @headers[&quot;Content-Type&quot;] = &quot;image/gif&quot;
       img = Magick::Image.new(200, 200)

       gc = Magick::Draw.new
       gc.gravity = Magick::CenterGravity
       gc.pointsize = 32
       gc.font_family = &quot;Helvetica&quot;
       gc.font_weight = Magick::BoldWeight
       gc.stroke = 'none'
       gc.annotate(img, 0, 0, 0, 0, &quot;Hello world!&quot;)

       img.format = &quot;GIF&quot;
       img.to_blob
     end
  end
end
</pre>
<p><br/></p>
<p><a name="heroku-dynos"><b>Understanding dynos</b></a></p>
<p>It is important to understand how <a href="http://docs.heroku.com/dynos">dynos</a> work. The bottom line is that you need one for every concurrent request. This is easy to demonstrate with the following modification of the Camping example above:</p>
<pre class="brush: plain; title: ; notranslate">
require 'camping'

Camping.goes :Hello

module Hello::Controllers
  class Index &amp;lt; R '/'
     def get
        render :hello
     end
  end
end

module Hello::Views
  def hello
     sleep 10
     p  &quot;Hello World!&quot;
  end
end
</pre>
<p>If you deploy this application to the free version of Heroku and then open two requests to it at the same time the second request will hang until the first one completes. This should illustrate why it is important to keep your processing quick and have enough dynos to match the concurrent request needs of your application.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ioncannon.net/programming/842/heroku-tips-for-the-cheap/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

