Setting up your Ubuntu Server for Merb 111

Posted by mikong on November 27, 2008

I prepared a documentation about this for a company and I thought I might as well post it here (modified a bit). I had to make sure the setup worked from scratch so I tested it using Sun’s VirtualBox.

Table of Contents

  1. Ubuntu Server
  2. Package Manager: apt-get
  3. Ruby
  4. RubyGems
  5. Apache 2
  6. MySQL
  7. Merb + DataMapper (+ SQLite 3?)
  8. Phusion Passenger
  9. Deploy the Merb App

1. Ubuntu Server

This setup was tested on the Ubuntu Server OS Hardy Heron, the latest version with LTS as of writing. Go to the Ubuntu website to download the installer of the Ubuntu version you want, preferably the latest with LTS.

The following instructions may work in other Debian-based OSes because it relies mainly on the apt-get package manager.

2. Package Manager: apt-get

Attribution: The content of this section, Package Manager: apt-get, is copied from Configure the Package Manager section of this Slicehost wiki page.

Ubuntu’s package management is done through apt-get. But it starts out handicapped. You need to edit a configuration file to add some additional sources.

sudo nano /etc/apt/sources.list

Uncomment these lines (remove the “# “; ignore if not commented out).

# deb http://archive.ubuntu.com/ubuntu/ hardy main restricted universe
# deb-src http://archive.ubuntu.com/ubuntu/ hardy main restricted universe
...
# deb http://security.ubuntu.com/ubuntu hardy-security main restricted universe
# deb-src http://security.ubuntu.com/ubuntu hardy-security main restricted universe

Now update the repository index and upgrade your built-in software:

sudo apt-get update && sudo apt-get upgrade

3. Ruby

To install Ruby, execute the following in the server’s command line:

sudo apt-get install ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 libreadline-ruby1.8 libruby1.8 libopenssl-ruby
sudo ln -s /usr/bin/ruby1.8 /usr/local/bin/ruby
sudo ln -s /usr/bin/ri1.8 /usr/local/bin/ri
sudo ln -s /usr/bin/rdoc1.8 /usr/local/bin/rdoc
sudo ln -s /usr/bin/irb1.8 /usr/local/bin/irb

4. RubyGems

First, install the essential tools for compiling:

sudo apt-get install build-essential

Then, install RubyGems (latest is version 1.3.1 as of writing; update the script if necessary):

mkdir sources; cd sources
wget http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
tar zxvf rubygems-1.3.1.tgz
cd rubygems-1.3.1
sudo ruby setup.rb
cd ~
sudo ln -s /usr/bin/gem1.8 /usr/local/bin/gem
sudo gem update --system

5. Apache 2

To install Apache, simply execute the following in the server’s command line:

sudo apt-get install apache2

6. MySQL

To install MySQL:

sudo apt-get install mysql-server mysql-client

Note: During installation, specify the root password for the MySQL when it’s asked.

7. Merb + DataMapper (+ SQLite 3?)

Unfortunately, installing the latest version of Merb (1.0 as of writing) requires SQLite 3. So for the moment,

sudo apt-get install sqlite3 libsqlite3-dev

Then, to install Merb and make it work with MySQL:

sudo gem install merb
sudo apt-get install libmysqlclient15-dev
sudo gem install do_mysql

8. Phusion Passenger

To install Passenger, do the following (from Phusion Passenger’s install page):

  1. Open a terminal and type:
    sudo gem install passenger
  2. Type:
    sudo passenger-install-apache2-module

    And follow the instructions.

Re-run ‘passenger-install-apache2-module’ if you were asked to install other dependencies. For example, if you followed the instructions in this document, you will probably be asked to install development libraries of apache2, so:

sudo apt-get install apache2-prefork-dev
sudo passenger-install-apache2-module

After that, you will probably be asked to edit your Apache configuration file (see /etc/apache2/httpd.conf) to add the following (note that version numbers may vary):

LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.0.3/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.0.3
PassengerRuby /usr/bin/ruby1.8

Since a Merb app is a Rack-based Ruby application, check out section 4 (or “Deploying a Rack-based Ruby Application” section) of the Phusion Passenger User’s Guide. From section 4.2 (or “Deploying to a virtual host’s root” section),

Add a virtual host entry to your Apache configuration file. The virtual host’s document root must point to the application’s public folder. For example,

  <VirtualHost *:80>
    ServerName www.yourdomain.com
    DocumentRoot /var/www/apps/my_app/public
  </VirtualHost>

Your Merb app needs to satisfy a certain directory layout for Passenger to work. This is described in section 4 of the User’s guide. In the root directory of your application, you need a public folder (which a standard Merb app should already have), a tmp folder (simply create an empty one), and a config.ru file containing the configuration detailed in section 4.5.4 of the User’s guide.

The Phusion Passenger User’s Guide is quite a comprehensive documentation. If you encounter any problems, be sure to check its other sections like the one on Troubleshooting. For example, if you have static assets (such as stylesheets) in your application’s public folder, you are likely to encounter the problem described in section 6.3.4. The solution is also there.

9. Deploy the Merb App

Basically, to get your Merb App to running you only need to do the following:

  1. Make sure the gem dependencies are satisfied by either installing the gems in your server, or freezing them in your app.
  2. Make sure your app satisfies the requirements of Passenger (i.e. tmp and public folders and config.ru file, see Phusion Passenger section above).
  3. Place a copy of the application in an appropriate directory such as /var/www/apps/my_app. Wherever it is, make sure that it is consistent with the specified directory in the Apache configuration file (see Phusion Passenger section above).
  4. Prepare your database: create it, configure your database.yml, and migrate your tables and data.
  5. Start your Apache server.
    sudo apache2ctl start

    Note that with Passenger, restarting your app is done by creating a restart.txt file in the Merb app’s tmp folder.

That should get you started. If you want more, there’s a great talk about Deploying a Merb App by Lindsay and you can download it from the MerbCamp videos page. It talks about freezing Merb and other gems, web servers, restarting your app, monitoring, configuration management, exception handling, and some other tips.

Quick notes for setting up a secure remote Git repository 80

Posted by mikong on August 29, 2008

Toolman Tim wrote a good article about setting up a remote Git repository. It didn’t include the part of creating a git user, so I’ve created my own notes below. His article does offer more explanation on the setup so be sure to check it out.

Prepare the bare Git repo:

$ ssh myserver.com
$ mkdir /var/git
$ mkdir /var/git/myapp.git
$ cd /var/git/myapp.git
$ git --bare init

Create your git user:

$ addgroup git
$ adduser -g git git
$ passwd git
$ chown -R git:git /var/git/myapp.git

Copy your local computer’s public key to the git user’s authorized keys:

$ vi ~/../git/.ssh/authorized_keys

Locate your git-shell:

$ which git-shell
/usr/local/bin/git-shell

And change your git user’s shell from /bin/bash to the git-shell path:

$ vi /etc/passwd

On your local computer, go to your project directory and point it to the remote server:

$ cd ~/dev/myapp
$ git remote add origin ssh://git@myserver.com/var/git/myapp.git
$ git push origin master

To set the remote repository as the default branch to push and pull to (so you don’t have to specify “origin master” with every push, pull, etc), open your project’s Git config:

$ vi ~/dev/myapp/.git/config

And add the following:

  [branch "master"]
    remote = origin
    merge = refs/heads/master

And that’s all there is to it!

Ruby 1.9 Hash in Ruby 1.8 145

Posted by mikong on April 03, 2008

I’m learning about Ruby 1.9 features but I realized I won’t be able to use it in any of my projects. So I thought of an exercise where I learn Ruby metaprogramming by trying to implement some of Ruby 1.9’s new functionality. Aside from learning metaprogramming and Ruby 1.9, I’d also end up with a library that I can use in my Ruby 1.8 projects.

But first, let me introduce…

The new Hash

We have an alternative hash syntax in Ruby 1.9:

  # old way that still works in Ruby 1.9
  my_hash = { :a => 'apple', :b => 'banana' }

  # new way
  my_hash = { a: 'apple', b: 'banana' }

A nice addition in Ruby 1.9 is that the order in which you added the items to a hash is remembered and will be used when the hash is iterated.

There’s also a new class method try_convert where if you call

  Hash.try_convert(myobject)

myobject’s to_hash method will be called to return a hash. If there’s no to_hash, nil will be returned.

And then we have these new instance methods (a few were simply borrowed from the Array class): assoc, compare_by_identity, compare_by_identity?, flatten, key and rassoc.

Trying Metaprogramming

Let’s first try to implement the try_convert class method. Luckily, Chris Wanstrath’s try() article gave us something we could use:

class Object
  ##
  #   @person ? @person.name :nil
  # vs
  #   @person.try(:name)
  def try(method)
    send method if respond_to? method
  end
end

By building on his code above, we could do this:

class Hash
  def self.try_convert(obj)
    obj.try(:to_hash)
  end
end

Looking at that, I’m starting to think Ruby 1.9 should have included the try() method instead of providing try_convert(). But that’s beside the point of this exercise.

Let’s try the simple instance method flatten. The documentation said it converts the hash to an array, then invokes Array#flatten! on the result. So it seems to be simply this:

class Hash
  ...
  def flatten
    to_a.flatten!
  end
end

But looking closer there’s actually a depth parameter (default is 1 - or so it seems but it behaves like -1 in my version of Ruby 1.9) demonstrated in the documentation’s example:

h = { feline: [ "felix", "tom"], :equine: "ed" }
h.flatten    # => [:feline, ["felix", "tom"], :equine, "ed"]
h.flatten(1) # => [:feline, ["felix", "tom"], :equine, "ed"]
h.flatten(2) # => [:feline, "felix", "tom", :equine, "ed"]

It turns out that the flatten and flatten! methods in Ruby 1.9 Array has also changed with a new level parameter. The default value of -1 makes it behave like the original (i.e. it recursively flattens the array). A level value of 0 performs no flattening and a level greater than zero flattens only to that depth (like the depth parameter in the Hash#flatten example above).

The flatten method we implemented above works fine. If you want the depth parameter, I’ve added it by first redefining the flatten method in Array, and then just calling that from the flatten method in Hash. You could head over to my GitHub repository to see the code. The simple project also implements some Ruby 1.9 Time class methods (sunday?, monday?, etc) using the method_missing trick. And I’ll continue to play around with Ruby 1.9 and metaprogramming so you could expect more Ruby 1.9 features in Ruby 1.8. The idea is not to port Ruby 1.9 to Ruby 1.8 (that would be crazy!), but to try stuff so some weird things may also crop up.