A collection of computer systems and programming tips that you may find useful.
 
Brought to you by Craic Computing LLC, a bioinformatics consulting company.

Friday, March 25, 2011

Rails 3 ActionMailer - defining default host

In Rails 3 ActionMailer is really easy to set up and use. Ryan Bates has a great Railscast on the topic that you should check out.

But I ran into one issue when creating emails that contain links back to my server.

Because you are sending an email to a remote machine, you need to include absolute URLs in your links.

You can define that in a config file but the example given in the Railscast is now deprecated, plus when I first tried it, my app was not picking it up and all my links were still relative.

You two things for this to work:

1: In your application.rb or environments/development.rb add a line like this in the configuration block, replacing craic.com with your domain
    config.action_mailer.default_url_options = { :host => "craic.com" }
The application.rb file applies to all environments. Putting this in development.rb or production.rb lets you use different hosts for each environment.

2: There are several ways to specify a url to pass into a link_to call in Rails - but only one seems to work.
Specify the urls for your links using <your_model>_url(<your_object>) - not <your_model>_path(<your_object>) and not url_for(...). I tend to use mymodel_path in links in regular web pages so I can't just cut and paste code into a mailer view.

Here is an example that works:
<%= link_to object.name, mymodel_url(object) %>

...produces...

<a href="http://craic.com/mymodels/1">My Object</a>




 

Friday, March 18, 2011

Tandem Select jQuery Plugin

A standard HTML multiple Select menu allows the user to select multiple options using Command-Click. But when the list of options is long, requiring the user to scroll, it becomes cumbersome and prone to errors.

An effective solution is to use two select menus in tandem, with buttons allowing options to be swapped between the two.

I'm pleased to announce the release of a new jQuery plugin that makes tandem selects simple to set up and easy to customize.

Tandem Select consists of a JavaScript function that leverages the jQuery library, a CSS file and template HTML code.

More information and live demos can be found on the Project Page and the software can be downloaded from the GitHub repository.




Monday, March 14, 2011

Adobe AIR Application Installer running flat out on MacBook


My MacBook (model 5,1 - few years old) running Mac OS X 10.6.5 has had a few incidents recently where it's responsiveness takes a nosedive. That typically means that some process is pegging the cpu at 100%.

I run into fairly frequent problems with Firefox, especially if a browser window is running Flash - say, for a video feed or an advert. Depending on the level of ambient noise in my office, I can even hear the fan and/or disk in the laptop running at full speed.

You can use the UNIX 'top' command in a shell to find out who the culprit is, plus other tools like 'lsof', etc. But I find the Apple desktop utility 'Activity Monitor' (in your Applications -> Utilities folder) is more useful. Open it up and select 'All Processes' in the select menu at the top of the window. Then click on the CPU tab down below and then on the cpu column to sort the processes in descending order based on % cpu utilization. Look for something that is up near 100 %.

If there is nothing striking then look for something with very high Real Mem and Virt Mem and check out the DiskActivity tab as you might have a process that is so memory hungry that it has to page data out to disk.

The example in the screenshot shown above is a straightforward CPU hog. It is the Adobe AIR Application Installer. I figure this is involved in installing the Adobe AIR runtime libraries that are used by Flash.

I have no idea why this is running in the first place - and why is it using 100% of my cpu? Flash and associated technologies can be great but they do seem to be around when I have problems...

If you have the same issue, just select the AIR Installer line in Activity Monitor and click the big red 'Quit Process' button.

Sorting Dates and Times in Ruby

Sorting an array of objects on a field that represents a time or date can be a bit tricky.

Take an example of a Rails ActiveRecord object with a standard 'created_at' column.

You can sort these with code like this:
myobjs.sort_by{|a| a.created_at}
This works but it is really sorting on the String representation of those dates. That may be good enough for some uses but not if you want to sort down to the minute and second and in particular, if you want to sort in correct descending order.

The best approach is to convert the date or time to the number of seconds since the epoch, which is an integer, and do a numeric sort on that.

A 'created_at' column has the class 'ActiveSupport::TimeWithZone' and this will output a String under most uses. Convert this to an integer with 'myobj.created_at.to_i' and then sort on that.
myobjs.sort_by{|a| a.created_at.to_i}


If you are working with Ruby Date objects, such as 'Date.today' this will not work. In most uses the Data will be converted to a string like this "Mon, 14 Mar 2011". If you try to convert the Date object directly to an integer with 'to_i' you will get an 'undefined method' error.

Here you need to explicitly convert to the epoch seconds format using 'strftime' and THEN convert that to an integer.
> today = Date.today
=> Mon, 14 Mar 2011
> today.strftime("%s").to_i
=> 1300060800


If you only have date strings, such as '2011-03-14', then you will need to convert these to Date objects using 'Date.parse' and then convert those to integers.

Working with dates and times can get messy but converting to integers is the best way to avoid complications.

 

Friday, March 4, 2011

simple-tooltip Ruby Gem for tooltip help

I'm pleased to announce the release of my first Ruby Gem: simple-tooltip

Simple Tooltip helps you make tooltip help available in your Rails 3 applications.

This is often done using a JavaScript plugin which produces a small popup window containing a short text string. That works great in many applications but often the help content that you want to provide is more extensive and you many want to include richer formatting, such as links to other web pages.

Simple Tooltip acts as a Rails Generator which will create a Tooltip model in your application along with a database table, a controller and views. You create help records using a web interface using plain text, html, Textile or Markdown formatting. The help records are stored in the database and retrieved using the unique, informative titles that you give them.

In your web pages you include a Tooltip helper that refers to the title of the relevant tooltip. Depending on how you set it up, when you hover over a tooltip icon or click on it, a popup window will appear displaying your help.

This is much richer and more flexible than the basic solutions available from JavaScript alone.

More than that, if the audience for your application is not just English-speaking, you can create multiple instances of each tooltip with content in each target language, identified by a two letter locale string. If a user has a non-English locale defined in your application, Simple Tooltip will look for content in the matching locale and display that. For content longer than single sentences, this is a more practical internationalization solution than I18n functionality built into Rails 3, which is more focused on shorter strings.

The gem is available at https://rubygems.org/gems/simple-tooltip.

The code is available at https://github.com/craic/simple_tooltip and is made freely available under the MIT license.



 

Tuesday, March 1, 2011

Passing Environment Variables to the nginx web server

I need to write this down for future reference...

With the Apache web server you can pass environment variables to Rails applications, etc by specifying them using SetEnv in your configuration file. But with nginx you don't do this - or at least you don't need to.

When you fire up the server, simply tell sudo to preserve your environment. Without that, sudo will reset all your variables. With it, they are available to nginx and your applications - nice and simple...
$ sudo -E /usr/local/sbin/nginx

Thursday, February 24, 2011

Rails, UTF-8 and Heroku

I've had problems with Ruby character encodings over the years, especially when pulling text with non-ASCII characters in from remote sites. I thought I had it mostly sorted but the past few days showed me that was not the case.

I have a MySQL database on my local machine and a Rails 3 app that pulls in text from remote sources, stores it in the database and does stuff with it. I am deploying the application on Heroku prior to public release. Heroku uses PostgreSQL exclusively.

I was under the belief that all the components in my system were set up to use UTF-8 encoding and therefore moving text with non-ASCII characters around should be fine. But in practice that was not the case - characters like 'α' that looked fine on my local machine showed up as 'α' on Heroku, etc. So clearly I was doing something wrong. Rather than go into all the gory details, this is the way to do it right...

Bottom-line: Make everything use UTF-8 explicitly ... EVERYTHING

0: Backup your current database!

1: MySQL
Here are the contents of my /etc/my.cnf file:
[mysqld]
datadir=/usr/local/mysql/data
bind-address = 127.0.0.1
character-set-server = utf8
max_allowed_packet = 32M
[client]
default-character-set = utf8
[mysql]
max_allowed_packet = 32M

Even if your tables are held in utf8, you should add these lines. You want the following mysql command to look as shown:
mysql> SHOW VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
+--------------------------+--------+

2: Rails
I'm using Rails 3 - can't tell you how this works in Rails 2.x
a: In config/application.rb make sure this line is uncommented:
    # Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
MySQL and Rails use different variants of utf8/utf-8 - make sure you are using the right one. And note the comment above this line - this sets up utf-8 encoding for templates ONLY.
b: In your database.yml, specify the encoding for the databases - for example:
development:
adapter: mysql2
host: localhost
encoding: utf8
[...]
Here you are telling the database adapter that the database uses utf-8.
c: mysql2
Notice that I am using the mysql2 adapter instead of mysql. At this point (Feb 2011) the mysql gem is NOT encoding aware. Replace mysql with mysql2 in your Gemfile and run bundle.
d: In each Model that uses text add this line at the very top of the file:
# encoding: UTF-8
This tells Ruby that we're using utf-8 in this model. I don't see a way to set this at the application level so you have to have to add it in all relevant model .rb file. I also don't like defining something with a comment line. I can't see how to define this in, say, an irb interactive session.

With all those components in place, you should be all set. Try entering non-ASCII characters into a form - such as accented characters or greek/math symbols. These should be displayed correctly in the browser and in the mysql command line client.

With regards to Heroku, assuming you have your app already set up, you should be able to do a 'heroku db:push' to copy the database into PostgreSQL on Heroku and the characters should display correctly on the remote pages. You will see reference to using 'heroku db:push' with explicit database URLs that include an encoding option, such as '?encoding=utf8'. If your MySQL is set up correctly then this should be unnecessary.

A critical part of running apps on Heroku is the ability to pull the database back to your local database using 'heroku db:pull'. Before getting all my components set up with utf-8, this step failed for me. With everything using utf-8, and after adding the 'max_allowed_packet' lines to my my.cnf file, this process works fine.

But because I was working with data in before everything was truly utf-8, I had some instances of text in the database that had been incorrectly encoded - and thereby effectively corrupted. I could see what the 'corrupt' characters looked like and I knew what the correct versions should be. Because everything is now using utf-8 I could simply do a substitution on the text. For example:
str.sub!(/ß/, 'β')
I gathered up the character mappings that I needed (which were not may in my case) and wrote up a class method that I cloned in each model with the issue. I then ran those in the Rails console to correct the bad characters. The method is:
  def self.make_utf8_clean
mappings = [ ['α', 'α'],
['ß', 'β'],
['β', 'β'],
['’', '’'],
['“', '“'],
['â€\u009D;', '”'],
['â€', '”'],
['ö', 'ö'],
['®', '®']
]
# Get the list of String columns
columns = Array.new
self.columns.each do |column|
if column.type.to_s == 'string'
columns << column
end
end

# Go through each object -> column against all mappings
self.all.each do |obj|
columns.each do |column|
mappings.each do |mapping|
value = obj.attributes[column.name]
if value =~ /#{mapping[0]}/
s = value.gsub(/#{mapping[0]}/, "#{mapping[1]}")
obj.update_attribute(column.name.to_sym, s)
end
end
end
end
end
This looks at your model and figures out which columns are of type String. It goes through all records and all character mappings, replacing text and updating the database as needed. Your mappings array could be much larger. There may be a better source of these, but this is a start.
You run this in a rails console like this:
Loading development environment (Rails 3.0.4)
ruby-1.9.2-p0 > YourModel.make_utf8_clean
It's a hack but it helped my 'fix' quite a few records that would have been a pain to recreate.

Character encodings are HARD - Yehuda Katz wrote a nice article on the issues. For most purposes (unless you work with Japanese text) UTF-8 is your best choice for encoding and so I'm using it exclusively. Java and Python both made the same choice and things are probably easier to set up in those worlds. Ruby has it's roots in Japan and so it is not surprising that it could not go down that path.

From now on, I'm going to make sure everything I touch is configured for UTF-8. There are fews reasons not to at this stage and it allows you to handle most languages.



 

Archive of Tips