Ruby on Rails 1.2.6: Security and Maintenance Release

The rails core team has released ruby on rails 1.2.6 to address a bug in the fix for session fixation attacks (CVE-2007-5380). The CVE Identifier for this new issue is CVE-2007-6077.

You should upgrade to this new release if you do not take specific session-fixation counter measures in your application. 1.2.6 also fixes some regressions when working with has_many associations on unsaved ActiveRecord objects.

Riding Rails: Ruby on Rails 1.2.6: Security and Maintenance Release

How Oracle Mix was built

We started coding about 3.5 to 4 weeks before Open World. At that point, we still didn’t have hardware and there were a ton of unknowns surrounding jRuby running on the Oracle AppServer (and if it did, what performance would be like). We bit the bullet and went for it. Rails was an essential ingredient to this project. I don’t know of other frameworks that would have enabled us to build this particular application so rapidly.

Oracle AppsLab » Mix, jRuby on Rails, Small Teams, Agile, and it’s Effects on the World

Ruby on Rails is the shit! 😉

Installing Ruby on Rails, Mongrel and use with Nginx and Apache

In this article I describe how to go about installing Ruby on Rails and Mongrel for use with Nginx or Apache on a linux machine. In my case the machine had Ubuntu Feisty installed but these instructions should be equally applicable on other linux distributions, like Red Hat, Fedora or Suse.

Please give feedback in the comments in case something didn’t work for you and how you solved it so that next person won’t have to go through the same problems. Improvements are also welcome.

First install Ruby

We’ll do it by compiling from source, like real men and women do. This gives us complete control of which version of Ruby that is used.

On Ubuntu make sure you have the build-essential, zlib1g-dev, openssl and libssl-dev packages installed. If you are using another distribution make sure similar things are installed.

  1. $ mkdir src
  2. $ cd src
  3. $ mkdir ruby-1.8.6
  4. $ wget ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.6.tar.gz
  5. $ tar xzf ruby-1.8.6.tar.gz
  6. $ cd ruby-1.8.6
  7. $ ./configure

If you get a checking size of int… configure: error: cannot compute sizeof (int) error first try to install the build-essential package. If that doesn’t help, you, like me, might have a busted libc6-dev installation. Reinstall that package ($ sudo apt-get –reinstall install libc6-dev). That fixed the problem for me.

The checkinstall package is a smart thing. If you build something from source it will create a distribution package for you so that you easily can remove the package later on. Install the package with apt-get install checkinstall. On a Debian or Ubuntu system checkinstall will create a dpkg package but if used on a Red Hat, Fedora or Suse system you will get a rpm package.

Now we can continue with installing ruby.

  1. $ make
  2. /etc/checkinstallrc and change INSTALL=1 to INSTALL=0 at the bottom of the file.
  3. $ sudo checkinstall
  4. $ sudo dpkg -i ruby_1.8.6-1_i386.deb

Then we install Rubygems

  1. $ cd ../..
  2. $ mkdir rubygems-0.9.4
  3. $ cd rubygems-0.9.4
  4. $ wget http://rubyforge.org/frs/download.php/20989/rubygems-0.9.4.tgz
  5. $ tar xzf rubygems-0.9.4.tgz
  6. $ cd rubygems-0.9.4
  7. $ sudo ruby setup.rb

If you get no such file to load — zlib (LoadError) you don’t have the zlib1g-dev package installed, which gave you a ruby without zlib support when you compiled it. Install the package and start over from the beginning.

And Ruby on Rails

  1. $ sudo gem install rails --include-dependencies

If you get the following error:

ERROR: While executing gem … (Gem::GemNotFoundException)
Could not find rails (> 0) in any repository

Just run the command again.

Now it’s time to install Mongrel

  1. $ sudo gem install mongrel
  2. $ sudo gem install mongrel_cluster
  3. $ sudo cp /usr/local/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.2/resources/mongrel_cluster /etc/init.d/

Test your Mongrel install by running Mongrel in the root of a Rails application. If it works you should be able to access your application at http://localhost:3000.

  1. $ cd rails_app
  2. $ mongrel_rails start -d
  3. Go to http://localhost:3000 with a browser (e.g. lynx)
  4. $ mongrel_rails stop

Now we need to do the cluster specific setup, do that by following these Using Mongrel Cluster instructions.

Capistrano installation

  1. $ sudo gem install capistrano
  2. $ cd rails_app
  3. $ capify .
  4. Edit the config/deploy.rb script and set the :application, :repository, :deploy_to, :user, :app, :web, :db variables
  5. $ cap deploy:setup
  6. $ cap -q deploy:check

If you don’t get You appear to have all necessary dependencies installed fix the errors you get and execute the command again.

If you get connection failed for: hostname (LoadError: no such file to load — openssl) you need to install the openssl and libssl-dev packages and then recompile ruby.

  1. Until Mongrel starts to include recipes for Capistrano 2.0 use the stuff from Mongrel and Capistrano 2.0
  2. In config/deploy.rb add the following:
    set :group_writable, false
    set :keep_releases, 2
    set :mongrel_conf, "#{deploy_to}/current/config/mongrel_cluster.yml"
    
  3. And at the end of the file add the following:
    after "deploy:symlink", :fix_session_permissions
    
    task :fix_session_permissions, :roles => :web do
      run "chmod 777 #{current_path}/tmp/sessions"
    end
    

Alright, let’s do the first deploy.

$ cap deploy

Naturally it won’t work. You might remember that we configured the mongrel servers to run as the mongrel user. For the servers to be able to write log files the shared/log directory has to be either world writable (not really wanted) or owned by the mongrel user (the preferred choice). So fix that on the deploy machine. At the same time do the same for the shared/pids directory.

Now create the needed database user, create the database and make sure the database.yml configuration file is correct. Then do another deploy and pray that it works!

Make the Mongrels start automatically at boot time

If you followed the Using Mongrel Cluster instructions you were told to copy a file to /etc/init.d/mongrel_cluster and then link to your mongrel_cluster.yml in the /etc/mongrel_cluster directory. That should be all the magic that is needed.

After you verified that it works run sudo update-rc.d mongrel_cluster defaults so it will be added to the services that are automatically started when the machine boots.

Nginx configuration

On this wiki page you can find a working site configuration. This is my /etc/nginx/sites-available/host file.

upstream host_mongrel {
        server 127.0.0.1:9100;
        server 127.0.0.1:9101;
}

server { listen 80; server_name host.se www.host.se; access_log /var/log/nginx/host.se.access.log;

    root   /u/host.se/www/current/public;
    index  index.html index.htm;

    location / {
            proxy_set_header  X-Real-IP  $remote_addr;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect false;

            if (-f $request_filename/index.html) {
                    rewrite (.*) $1/index.html break;
            }
            if (-f $request_filename.html) {
                    rewrite (.*) $1.html break;
            }
            if (!-f $request_filename) {
                    proxy_pass http://host_mongrel;
                    break;
            }
    }

    error_page   500 502 503 504  /50x.html;

    location = /50x.html {
            root   html;
    }

Configure Apache

<

p>I haven’t done this myself but it should be fairly easy to follow the instructions in the Configuring Apache 2.2, Mongrel and mongrel_cluster section in this Deploying Rails on Ubuntu Dapper article.

<

p>You might need to do the following to the get the needed apache2 modules enabled.

  1. $ sudo /usr/sbin/a2enmod proxy_balancer
  2. $ sudo /usr/sbin/a2enmod headers

Sources

Rails 2.0: Preview Release

Behold, behold, Rails 2.0 is almost here. But before we can slap on the final stamp, we’re going to pass through a couple of trial release phases. The first is this preview release, which allows you to sample the goodies in their almost finished state.

We might change a few things or add something else, but by and large, this is how Rails 2.0 is going to look and feel. After this release have had a chance to be tried out, we’re going to move to a release candidate or two (or three, depending on how many we need). Then, the final release.

Before the release of 2.0, we’re also going to be putting out 1.2.4, which will include a variety of bug fixes and the last deprecation warnings to get you ready for upgrading an existing application to 2.0 standards.
Enough about process. Let me tell you a little bit about what’s new in Rails 2.0:

Riding Rails: Rails 2.0: Preview Release

Not too many bigger changes but a lot of small improvements.

Crain’s Chicago Business interviews Jason of 37signals

Crain’s Chicago Business recently posted a video interview with Jason where he discusses avoiding structure, how interruption is the enemy of productivity, why it’s a good idea to emulate drug dealers, the secret to competing with free stuff, and more. Check it out.

Crain’s Chicago Business interviews Jason – (37signals)

Not really any surprises for us readers of their blog but if you’re not sure who 37signals are and what they do. Watch this video!

Rails + Tidy + REXML

It wasn’t totally straight forward to get Tidy, REXML and Rails to play together, so I thought I would write down what and how I did it to save time for others.

The reason for doing this is that I get text in (X)HTML format through RSS feeds and I want to make excerpts of it. So given a long text as input I want to make a short extract of it.

After a bit of thinking and googling I figured out that slicing a HTML document after a given amount of characters is not super trivial to do. Because of the tags you need to actually parse the HTML document and keep track of which tags you need to close then reaching the given amount of characters. Luckily for us Mike Burns has already written a function for Truncating HTML in
Ruby
. Perfect!

However, after adding that piece of code (and unit tests for that of course) you will find out that REXML barfs if the input is not well-formed HTML and naturally having no control of the content of the RSS feeds there is no way you can guarantee that.

Luckily Tidy comes to the rescue. Tidy is a library that corrects invalid HTML. Install the tidy library and then the tidy ruby gem.

gem install tidy

Unfortunately you have to manually set the path to the library before you can use it with

Tidy.path = '/usr/lib/tidylib.so'

If you, like me use an apple laptop for development and linux on the server that path is going to be different between the environments. So what I did was to introduce a constant in the rails environment files. In the config/environments/production.rb file I put:

TIDY_LIB_PATH = '/usr/lib/libtidy.so'

And naturally I set it to the correct path for my powerbook in the config/environments/development.rb file. Then I just do

Tidy.path = TIDY_LIB_PATH

before using Tidy and everything is good.

To make Tidy behave decently you need to set the following options:

  • tidy.options.show_body_only = true – don’t output body and html tags
  • tidy.options.output_xhtml = true – output xhtml
  • tidy.options.wrap = 0 – don’t write newlines all over the place
  • tidy.options.char_encoding = ‘utf8′ – use utf8 to play nice with rails

so in the end this is what I ended up with:

require 'rexml/parsers/pullparser'
require 'tidy'</p>

<p>def make_excerpt
excerpt = slice(tidy_up_html(content), 2000)
end</p>

<p>def tidy_up_html(html)
Tidy.path = TIDY_LIB_PATH</p>

<p>cleaned_up = Tidy.open do |tidy|
tidy.options.show_body_only = true
tidy.options.output_xhtml = true
tidy.options.wrap = 0
tidy.options.char_encoding = 'utf8'
cleaned_up = tidy.clean(html)
cleaned_up
end
end</p>

<p>def slice(string, length, ellipsis = '...')
p = REXML::Parsers::PullParser.new(string)
tags = []
new_len = length
results = ''
while p.has_next? &amp;&amp; new_len &gt; 0
p_e = p.pull
case p_e.event_type
when :start_element
tags.push p_e[0]
results &lt;&lt; &quot;&lt;#{tags.last} #{attrs_to_s(p_e[1])}&gt;&quot;
when :end_element
results &lt;&lt; &quot;&lt;!--#{tags.pop}--&gt;&quot;
when :text
results &lt;&lt; p_e[0].first(new_len)
current_len = new_len
new_len -= p_e[0].length
if new_len &lt; 0</p>

<h1>find next dot</h1>

<p>i = p_e[0].index('.', current_len)
results &lt;&lt; p_e[0].slice(current_len, i-current_len) if i
results &lt;&lt; p_e[0].slice(current_len, p_e[0].length) unless i
results &lt;&lt; ellipsis
end
else
results &lt;&lt; &quot;&lt;!-- #{p_e.inspect} --&gt;&quot;
end
end
tags.reverse.each do |tag|
results &lt;&lt; &quot;&lt;!--#{tag}--&gt;&quot;
end
results
end

I modified Mike Burns’ method so that after the given number of characters has been reached it will still include text until the next ‘.’ character. I figured it’s much nicer with an excerpt that ends with a complete sentence.

Feel free to use this code if you want.