Formatting Text

For text fields one typically wants to allow some HTML tags, add support for link breaks and even auto link URL’s and emails.

This method which I got from this forum thread, Adding a line break … safely, does all of this and is a must add to my application_helper.rb.

def format_content(content)
  # allow only tags specified in tags options, likewise in attributes
  content = sanitize(content, :tags => %w(b strong i em img), :attributes => %w(src))

  # add support for line breaks
  content = simple_format(content)

  # auto link URL's and emails
  content = auto_link(content, :all, :target => '_blank')

  return content
end

rake db:migrate hangs

Recently I tried running my RoR applications on Oracle.

I noticed that when I ran rake db:migrate it would hang. Specifically it would hang during the schema dump phase.

E:\work\sandbox>rake db:migrate --trace -v
(in E:/work/sandbox)
** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:migrate
** Invoke db:schema:dump (first_time)
** Invoke environment
** Execute db:schema:dump

I realized later that this was because the schema dump phase is very slow and the database I was using had many other tables from other applications. When I left it running it finally completed after 10 minutes.

You can see the slow progress of the schema dump phase by tailing schema.rb in the db directory.

Ruby on Rails and Oracle

  1. Get the Ruby OCI8 driver.  Download the file that ends with “mswin32.rb” and install like this:
    E:\ruby>ruby ruby-oci8-1.0.3-mswin32.rb
    Copy OCI8.rb to e:/ruby/lib/ruby/site_ruby/1.8/DBD/OCI8
    Copy oci8.rb to e:/ruby/lib/ruby/site_ruby/1.8
    Copy oci8lib.so to e:/ruby/lib/ruby/site_ruby/1.8/i386-msvcrt
    OK?
    Enter Yes/No: Yes
    Copying OCI8.rb to e:/ruby/lib/ruby/site_ruby/1.8/DBD/OCI8 ... done
    Copying oci8.rb to e:/ruby/lib/ruby/site_ruby/1.8 ... done
    Copying oci8lib.so to e:/ruby/lib/ruby/site_ruby/1.8/i386-msvcrt ... done
    OK

    You can test the driver by running a query using Ruby.

    E:\>ruby -r oci8 -e "OCI8.new('foo','12345','sid').exec(
    'SELECT * from users') do |r| puts r.join(' | ') ; end"
  2. Install the ActiveRecord Oracle adapter.gem
    E:\ruby>install activerecord-oracle-adapter --source http://gems.rubyonrails.org
  3. Update config/database.yml to connect to Oracle
    development:
      adapter: oracle
      database: sid
      username: foo
      password: 12345
      timeout: 5000
  4. Test by doing a rake db:migrate.
  5. Test by running the Ruby on Rails server and making sure there are no errors upon startup.

This article is based on these articles.

Twitter and Rails

Twitter has become the poster child of why not to use Ruby on Rails.  Recently a friend of mine started a company and when I noticed he used PHP I asked why he didn’t use Rails.  He responded “Twitter uses Rails and they keep going down.  Facebook uses PHP.  We’ll use PHP.”

There is an interesting interview w/ Twitter developer Alex Payne about the issues Twitter has had with Ruby on Rails.

The common wisdom in the Rails community at this time is that scaling Rails is a matter of cost: just throw more CPUs at it. The problem is that more instances of Rails (running as part of a Mongrel cluster, in our case) means more requests to your database. At this point in time there’s no facility in Rails to talk to more than one database at a time. The solutions to this are caching the hell out of everything and setting up multiple read-only slave databases..

All the convenience methods and syntactical sugar that makes Rails such a pleasure for coders ends up being absolutely punishing, performance-wise. Once you hit a certain threshold of
traffic, either you need to strip out all the costly neat stuff that Rails does for you (RJS, ActiveRecord, ActiveSupport, etc.) or move the slow parts of your application out of Rails, or both.

It’s also worth mentioning that there shouldn’t be doubt in anybody’s mind at this point that Ruby itself is slow. It’s great that people are hard at work on faster implementations of the language, but right now, it’s tough. If you’re looking to deploy a big web application and you’re language-agnostic, realize that the same operation in Ruby will take less time in Python. All of us working on Twitter are big Ruby fans, but I think it’s worth being frank that this isn’t one of those relativistic language issues. Ruby is slow.

In April 2007, former Chief Architect Blaine Cook made a presentation called Scaling Twitter.  It’s a well done presentation, even if everything is black.

In May 2008 there were rumors that Twitter was abandoning Rails.  SitePoints believes it is not a framework issue but rather an architectural issue that is causing Twitter’s problems.

There are many large sites that run Rails well and many smaller ones that do not.  It seems like another case of the “leaky abstraction” where we have such a nice framework that we think we can abstract away issues like scaling but in the end when the site becomes big enough we have to look under the covers.

Ruby has been documented to have I/O issues and general performance issues.  Like PHP before it looks like Ruby needs to mature more and deal better with scaling and I/O issues.  I am confident though this will happen because of the tremendous momentum of Ruby on Rails.  However I am keeping on eye on Django, especially now that Google has thrown its large hat into Django’s ring.

Monit and Mongrel

This post about Monit and Mongrel is based on this fantastic post, Monit makes Mongrel play nice!

Install Monit from source:

$ wget http://www.tildeslash.com/monit/dist/monit-4.10.1.tar.gz
$ tar xvfz monit-4.10.1.tar.gz
$ cd monit-4.10.1
$ ./configure -prefix=/usr  (the default prefix is /usr/local)
$ make
$ make install

Configure Monit:

In the monit source you will find a sample monitrc which is completely commented out. You can then copy it to wherever you like and then edit it. Here is my monitrc.

# Start monit in the background (run as a daemon) and check services at
# 1-minute intervals.
set daemon  60

# Set logging.
set logfile /tmp/monit.log

# Set the list of mail servers for alert delivery.
set mailserver localhost

# Set alert recipients.
set alert foo@example.com                # receive all alerts

# Start Monit's embedded web server.
set httpd port 2812 and
     allow admin:monit      # require user 'admin' with password 'monit'

# Mongrel - Development
# Check that Mongrel is running and that it responds to HTTP
# requests. Check its resource usage such as cpu and memory. If the
# process is not running, monit will restart it by default. In case
# the service was restarted very often and the problem remains, it is
# possible to disable monitoring using the TIMEOUT statement.
check process mongrel-dev with pidfile /rails/log/mongrel.pid
    start program = "/usr/bin/mongrel_rails start -d  -c /rails
                          -p 3000 -P /rails/log/mongrel.pid"
    stop program  = "/usr/bin/mongrel_rails stop
                           -P /rails/log/mongrel.pid"
    if cpu > 50% for 2 cycles then alert
    if cpu > 80% for 5 cycles then restart
    if totalmem > 60.0 MB for 5 cycles then restart
    if loadavg(5min) greater than 10 for 8 cycles then restart
    if failed port 3000 protocol http
       with timeout 15 seconds
       for 2 cycles
       then restart
    if 3 restarts within 5 cycles then timeout
    group mongrel-dev

After you are done configuring monitrc copy it to /etc.

$ sudo cp monitrc /etc

To test the configuration:

$ sudo monit -t

Run Monit:

To start monit:

$ sudo monit

To restart monit:

$ sudo monit reload

To stop monit:

$ sudo monit quit

To see monit’s log (assuming you are using my configuration):

$ tail -f /tmp/monit.log

Learn More:

Monit Getting Started
Monit Manual

My First Rails 2.0 Application w/ Restful Authentication

Today I took the plunge and installed Rails 2.0.2. Notes on the Rails 2.0 release can be found here.

Here are the steps I took.

  1. Upgrade Ruby Gems to the latest version (in this case 1.0.1).
    gem update --system
  2. Install Ruby on Rails 2.0.2.
    gem install rails -v 2.0.2
  3. Install MySQL gem (as of March 5, 2008, it is version 2.7.3) and add MySQL executable to path.
    gem install mysql
  4. Create prayer application.
    rails prayer -d mysql
  5. Install Restful Authentication plugin.
    cd prayer
    ruby script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/
  6. Create scaffold for prayer model.
    ruby script/generate scaffold Prayer title:string body:text

    The first thing I noticed different about Rails 2.0 is that the scaffold now also generates the model and data migration file with title and body as columns in the prayer table. Also the format of the data migration file is slightly more compact.
  7. Create user model with authentication. The --include-activation flag is to create the mailers for activation and signup notification.
    ruby script/generate authenticated user sessions --include-activation
  8. Configure config/database.yml and then create prayer and user tables in DB.
    rake db:migrate
  9. Configure SMTP settings.
  10. Modify app/models/user_mailer.rb, replacing the place holders with constants which you can configure with different values for different environments using config/environments/development.rb, config/environments/production.rb.
  11. Modify user_observer.rb to incorporate the reset and forgotten password features.
  12. Create scaffold for role model. Add an admin user.
    ruby script/generate scaffold Role rolename:string
  13. Create permission model. Modify role and permission models to know about each other.
    ruby script/generate model Permission
  14. Modify user model to use permissions.

Much of this post is based on this excellent post, Restful Authentication with all the bells and whistles.  At this point I did not continue with much of the tutorial, especially with parts like password forgotten, separate account controller, etc.

‘Error in my_thread_global_end()’ when running rake db:migrate

When I run rake db:migrate I get this error at the end.

Error in my_thread_global_end(): 1 threads didn't exit

I pinned it down to this code in one of my migration files.

# create admin user
user = User.new
user.login = 'admin'
user.password = 'password'
user.save(false)

If I don’t run user.save(false) I don’t get the error. I am not sure why, the user does get saved properly to the database.

I saw this post on the MySQL forums that seemed to indicate it was an issue with libmySQL.dll. So I upgraded my MySQL instance from 5.0.27 to 5.0.51a. Of course this did not go smoothly, I got this error when trying to reconfigure the MySQL server instance “MySQL service could not be started error 0”. Fortunately another post on the MySQL forums, Could not start service : Error 2003, solved this problem for me. I just had to remove the following files from the mysql/data directory.

  • ib_logfile0
  • ib_logfile1
  • ibdata1

Unfortunately when I then did a rake db:migrate I saw this error.

Mysql::Error: Table 'prayer.schema_info' doesn't exist:
SELECT version FROM schema_info

After deleting and recreating the database I was finally able to run rake db:migrate. Unfortunately I still got the same error that inspired this post.

Googling some more I saw a MySQL bug report, MySQL Bugs: #25621: Error in my_thread_global_end(): 1 threads didn’t exit. Apparently this is a client side issue and I think I can safely ignore it though it is quite annoying.

Strictly speaking, this is not MySQL bug. This is a client bug – a client application (PHP, probably) linked with libmysqlclient calls my_thread_init() but does not call my_thread_end() as appropriate (doesn’t call at all or calls too late). MySQL client library detects this and issues a warning.

On the other hand, we can just remove the check and let buggy applications to fail some other way. Not calling my_thread_end() is a guaranteed memory leak. Calling it too late could easily crash the application.

Problem updating restful_authentication plugin

I tried to update the restful_authentication plugin by doing this.

$ ruby script/plugin update restful_authentication

Unfortunately it didn’t do anything.

I know I don’t have the latest version because in another project I pulled down the latest restful_authentication code and it was different.

To get around this I forced an install with the latest code.

$ ruby script/plugin install -x \
    http://svn.techno-weenie.net/projects/plugins/restful_authentication/

Fortunately I received an answer about this on the rails mailing list. Apparently update only works if the plugin is in svn:externals. To do this you would install it with the -x flag (see list of flags by doing ruby script/plugin install -h’).

However if you try this with the restful_authentication plugin you’ll see this.

$ ruby script/plugin install -f \
    http://svn.techno-weenie.net/projects/plugins/restful_authentication/
Cannot install using externals because this project is not under
subversion.