Rails 2.2 has straightforward, plugin-free support for timezones and localization. Woot to rails core, goodbye to tzinfo.
But what if you need to use a variable using a MySQL::time column – like lunch_time that describes a time of day? Lets use the example of an ActiveRecord class Schedule with a column lunch_time. A function like1 2 3 |
def missed_lunch?(sched) Time.zone.now > sched.lunch_time + 30.minutes end |
doesn’t work. Why? MySQL::time columns are 24-hour naked times (like 13:30:04), with no zone, date, or AM/PM within MySQL. When loaded by AR the column is converted into a Ruby::Time object in UTC time on 1/1/2000, since Ruby has no native time_of_day-like class. 9:15 (in MySQL::time) becomes Sat Jan 01 9:15:00 UTC 2000 ( in ruby Time).
Time.zone.now). It’s best to tackle this problem at the model level, so the rest of our code can deal with time_of_day consistently. We extend ruby Time with a method to convert unruly MySQL::time columns into local-zone, ‘today’ times:
1 2 3 4 5 |
class Time
def from_mysql_time
return Time.zone.now.change(:hour => self.hour, :min => self.min, :sec => self.sec)
end
end |
1 2 3 4 5 6 7 |
class Schedule < ActiveRecord::Base
# lunch_time time
(...)
def lunch_time
read_attribute(:lunch_time).from_mysql_time
end
end |
>> Time.zone.now
=> Wed, 11 Mar 2009 11:46:51 EDT -04:00
>> my_sched.lunch_time
=> Wed, 11 Mar 2009 12:30:00 EDT -04:00
>> missed_lunch?(my_sched)
false
This solution works consistenly for all timezones. If your app uses localization, you can relax knowing your time_of_day comparisons will be done correctly in any Time.zone
Everyone agrees that MySQL alone isn’t a great solution for text searching. Whenever the need arises, I’ve always recommended jumping ship to sphinx. And sphinx is great – it works, it’s highly customizable, and it’s free. But it doesn’t really come for free, it has overhead. You have to manage your indexer cron jobs, hack up capistrano, and teach your developers how to use it. It also makes managing multiple environments (staging, local development, etc) a more tangled hairball. That’s all expensive in terms of time, management, communication, and complexity.
So consider the tradeoffs carefully. Sphinx is a much better hammer to the nail of text searching. But it takes a lot of work. For a recent project, we decided to revisit the idea of text searching within MySQL. Wat is the best we could do with MySQL alone, and would it be sufficient? It turned out good enough. Here’s what we learned:
InnoDB
You can’t search a text field without a decent index, and you can’t index a text field properly in an InnoDB table. MyISAM will work (and it’s generally faster than InnoDB), if you can handle table level locking. Basically, if you’re doing very, very few writes (INSERT, UPDATE, DELETE) and many of reads (SELECT), you may be able to tolerate this. Migrate to change table types and build an index:
1 2 3 4 |
# change the table type execute "ALTER TABLE `orders` ENGINE = MyISAM;" # create new index execute "CREATE FULLTEXT INDEX my_orders_text_index ON orders (text_field)" |
Google to read a lot more about mysql, MyISAM, and InnoDB.
boolean full-text search
I’ve seen simple_search.rb used before in rails projects. SimpleSearch uses the mysql LIKE string comparison function, which only works for text fields in Innodb tables, which are by definition not text index-able. So while this solution may appear to work, it could be unwise to build a production site using SimpleSearch.
If you are searching google-style (multiple words, fragments, etc), it’s likely you will use mysql’s boolean full-text search. For our app, we gsub’ed in the logic operands and did a named scope all at once:
1 2 |
named_scope :like_text, lambda { |str| {:conditions =>
["match(text_field) AGAINST(? IN BOOLEAN MODE)", str.gsub(/(\S+)/, '+\1*')] } }
|
config
You’ll also want to pay close attention to your MyISAM settings in my.cnf, as well as your stopwords files and word length setting. Example:
1 2 |
ft_min_word_len = 2 ft_stopword_file = |
An empty stopword file means no stopwords. Make sure you make mysql config changes on all of your db servers.
When all is done, you should be able to quickly search using your MyISAM indexed text field using a named scope:1 |
cheesey_sandwichy_orders = Order.like_name("sand chee")
|
Mmmm, tasty.
If Sphinx is required, there are several plugins to help Sphinx and Rails jive. We’ve used ultrasphinx with moderate success, though it’s limited in terms of flexibility. There’s also sphincter (snicker) and acts_as_sphinx.
Not too long ago Peter wrote about BrowserWar and the IEWarfare project. BrowserWar is now available as a Rails plugin at github.
The BrowserWar plugin helps you detect IE, and enables easy detection and custom display messages of any browser/version. To install the BrowserWar plugin in your rails project simply type:
script/plugin install git://github.com/sagebit/browser_war.git
Default Usage:
1 2 3 |
startbrowserwar({:browsers => browserwarbrowsersdefault,
:message => browserwarmessagedefault,
:options => browserwaroptionsdefault})
|
1 |
<%= javascript_include_tag(:defaults, 'browserDetect', 'browserWar') %> |
And that’s it! For more information checkout the README for the plugin. Head over to IEWarfare.com for more info.
Running rails applications with Apache has never been great. In the past, options have been (from best to worst):
- proxy to mongrel or another appserver using mod_proxy or mod_proxy_balancer
- mod_fcgid
- mod_ruby (gasp)
Now there is a new player on the scene, Phusion Passenger. I haven’t used it yet in for a high traffic site, but for a tiny project it worked like a charm with no hiccups. Just do: (these steps are for Apache 2.0.52)
sudo gem install passenger
passenger-install-apache2-module
Follow the instructions and create /etc/apache2/conf.d/passenger:
1 2 3 |
LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.3/ext/apache2/mod_passenger.so PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.3 PassengerRuby /usr/local/bin/ruby |
1 2 3 4 |
<VirtualHost www.foobar.com:80>
ServerName www.foobar.com
DocumentRoot /webapps/foobar/public
</VirtualHost> |
touch /webapps/foobar/tmp/restart.txt
to reload rails whenever you update your code. Brilliant!
MarkItUp! is a cool textile editor. It is fairly easy to integrate with Rails, but it relies on jQuery, so you must make the jQuery function calls and the Prototype function calls play nice with each other.
At the bottom of the jQuery file add:
/* Set jQuery to run in no-conflict mode */
var J = jQuery.noConflict();
Then if you initialize your MarkItUp! editor like this:
def markitup_editor_initialize
"<script type=\"text/javascript\" >
$(document).ready(function() {
$(\".markItUpTA\").markItUp(mySettings);
});
</script>"
end
Just convert the ’$’ to ‘J’, or whatever you named your no conflict mode jQuery in the first step:
def markitup_editor_initialize
"<script type=\"text/javascript\" >
J(document).ready(function() {
J(\".markItUpTA\").markItUp(mySettings);
});
</script>"
end
And you are done. You can use this trick for any sweet jQuery tools you have running around your Rails app!
A BrowserWar is coming soon to an interweb near you!
The source is available on Github, or there’s my fork of it.
Matt Long, of Sagebit, and I wrote it over the past few days. It will kick crappy browsers right in the face!!!
Fork and tweak to your heart’s content! Please send pull requests if you find any bugs or new features.
It is the first open source project Sagebit has released on our new website.
Soon we’ll release a Ruby on Rails plugin that gives you a neat helper method to set up a browser war in your view templates to fight IE, or whatever other browser you have a vendetta against.
Example usage (edit bottom of browserWar.js, or can be called within a script tag in HTML files):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Examples (edit bottom of browserWar.js, or can be called within <script> tag in HTML files):
browserwar.setup();
browserwar.klass('', 'browser_warning', true);
browserwar.message('<p>This site is optimized for the <a href="http://www.mozilla.com/en-US/firefox/"> Mozilla
Firefox</a> browser.</p>' +
"<p>It looks like you're using <b>" + browserwar.browser_display_name + " " + BrowserDetect.version + "</b> or older.
To get the best experience from this site we suggest you upgrade your browser.</p>" +
'<p>Click the image below to learn more about alternative browser options.</p>' +
'<a href="http://browsehappy.com/browsers/" title="Browse Happy: Switch to a safer browser today"><img
src="http://browsehappy.com/buttons/bh_185x75.gif" alt="Browse Happy logo" width="185" height="75"></a>');
browserwar.position('90px','0px','200');
browserwar.linkcolors('blue','red','purple')
browserwar.style('200px','20px','8px ridge #CE8DAD','#fff','#000');
browserwar.fight('Explorer', 6);
browserwar.fight('iCab');
browserwar.run();
|
Sweet! IE will lose the war!
Syntax coloring is awesome. How to do it easily in Mephisto? The pieces are all there. CodeRay is a wicked syntax highlighting library written in Ruby, included for free via the filtered_column_code_macro plugin in Mephisto.
Then we get:
1 2 3 4 |
# I am awesomely colorized and numbered def mult(a,b) @product = a * b end |
instead of
# I am so 1999
def mult(a,b)
@product = a * b
end
To enable CodeRay, all you need is love css. Just upload your favorite CodeRay css style, either directly into your project, or via ‘Design’ from within Mephisto admin. That’s it – just add and include the right css.
Good CodeRay css styles we found in the ether: one two three four
Once your css is in the project, include it in your default or target liquid layout:
{{'your_coderay_css' | stylesheet}} |
and wrap your code in
<macro:code lang="ruby">
YOUR CODE HERE
</macro:code>
That’s it – just add and include the right css.
Next to be done:- gracefully disable line numbers
- work well with other langs (javascript, css)
- integrate with pre-code tags (like redmine does)
- docs in mephisto
- http://blog.tupleshop.com/2006/7/20/code-syntax-highlighting-in-mephisto-with-coderay
- http://offtheline.net/2007/1/12/mephisto-stepping-stone-theme
- technoweenie
As I have stated in a previous blog post, the Google Maps API with the YM4R/GM plugin has provided us with great potential for our Cartabuzz project. However, Cartabuzz was recently and temporarily hindered by Google’s version control.
Earlier today, we continued work on some features for the next Cartabuzz rollout when, much to our surprise, the Google Map controls (zoom controls, scale bar, even the ‘powered by Google’ icon) were gone. Using Firebug we noticed that the div tags for the controls were being created properly, and the proper Javascript was executing correctly without errors, yet our controls were simply not appearing on the map. Even when we rolled back to a much earlier revision, our controls would not appear. Therefore, the issue must have been with Google Maps itself, as functionality that worked in a previous revision was suddenly broken.
It turns out that recently, Google released v2.133d, thus pushing v2.133d to v2.x and pushing v2.132d (the version we were using) to v2 (article explaining this can be found here). Apparantly, this latest update to Google Maps API caused an incompatibility somewhere in our application. Therefore, we modified the YM4R/GM plugin code in our project to use v2.132d instead of v2.x, and now Cartabuzz is functioning properly again.
To those of you who are using YM4R/GM in your Rails projects and cannot find where the Google Maps API version is specified, look in vendor/plugins/ym4r_gm/lib/gm_plugin/map.rb. Within the self.header method definition, find the line similar to the following(should be line 34):a = "<script src=\"http://maps.google.com/maps?file=api&v=2.x&key=#{api_key}&...</script>\n" |
One thing is usually true about developing any web application, it is always nice to have just a little bit more storage space. While developing Sagebit’s PICasso application, I realized that there are times when it is nice to have storage space not on your application and development machine. This is especially true if you expect to be handling large file sizes (e.g. high-resolution pictures or video files). Thankfully Ruby on Rails developers have a pretty convenient option at their disposal, Amazon Simple Service Storage a.k.a Amazon S3.
What is great about Amazon S3 is that it provides reliable data storage service that not only assists scalability of your Rails web applications, but it is also very cheap. In addition to this service being very cost-effective, it supports REST which any good Rails developer will tell you is great. And perhaps most impressive about Amazon S3 is how easy it is to actually integrate into your web application.
First create an Amazon Web Services account, and sign up to use S3 on Amazon. You will be given an access key id and a secret access key for your account. Then you create a bucket…yes a bucket. A bucket is like a folder that will hold all your files. For managing buckets for your S3 account, it is best to use a GUI application. Being an OS X Rails developer I would reccomend the S3 Browser. There are other S3 management applications out there for other operating systems too. You might also want to check out the Firefox addon . I would however, recommend, that you use a standalone application.If your using the S3 Browser, you just need to create a New Connection by entering you access key id and secret access key that you got when you created your Amazon account. There will be a similar option for other S3 GUI’s. You now will have the ability to manage buckets (e.g. delete, create, move, etc.) using the GUI application.
Now, time to integerate Amazon S3 into your Rails application. You first need to install the S3 gem:
sudo gem install aws-s3
Your Rails application also needs to know how to handle your Amazon S3 account specific to each environment. So will have to edit the amazon_s3.yml that gets created when you install the gem. Notice how similar it is to your database.yml.
All you have to do now is edit it. Enter your access key id and secret access key’s plus specify the bucket names:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
development: bucket_name: picasso_development access_key_id: xxxxxxx secret_access_key: xxxxxxxxxxxx test: bucket_name: picasso_test access_key_id: xxxxxx secret_access_key: xxxxxxxxxxxx production: bucket_name: picasso_production access_key_id: xxxxxx secret_access_key: xxxxxxxxxxxx |
What’s next…well that’s it! You’re done. You can now use your Amazon S3 buckets for storage. The great thing about Amazon S3 is that it has been widely accepted by the Rails community. So you will find plenty of plugins and applications that use this service. And so if you’re using attachment_fu to upload you picture files as we did in PICasso, you can tell attachment_fu to store your pictures on your S3 account simply by specifying this in your picture model:
has_attachment :content_type => :image, :storage => :s3, :size => 40.megabytes |
Attachment_fu is another useful and quite popular Rails plugin, but I won’t go into too much detail about it today…perhaps it will be a topic for another blog post.
So that was it, a simple integration of Amazon S3 for your Rails application. For me S3 relieves a burden of not having to worry about where my application’s data is and what state it is in. I find that keeping such application data separate form where the actual application is helps insure their safety.
In my next blog post I will discuss how we used the boling-for-batches plugin, written by Sagebit’s own Rails Guru Peter Boling , to upload a very large set of pictures to our Amazon S3 buckets.
We started scraping as part of the Mail Yeti project. We wanted to expand our functionality by searching other sites on the web against our incoming emails to begin building a useful database of hoax emails. As part of our response to users that submit suspicious emails, we wanted to give them some information regarding the chance their email could be a hoax. We have been working on returning links to similar hoax emails found using Hpricot.
Hpricot is a powerful Ruby gem that allows you to search through HTML tags in a web page for specific data. Learning how to use Hpricot has proven very useful. It has helped us get up to speed very quickly with one of our current client’s projects. With current web standards being ignored by so many sites, getting the data our client requires has been a challenge. Digging through web pages constructed entirely with tables, and no consistency in how they display information has been brain wracking, but it has expanded my knowledge of Hpricot and its capability exponentially over the past few weeks.
Another great web scraping gem I am beginning to look at is WWW::Mechanize. It allows you to have a virtual user in your code that can interact with forms and buttons on a page.
With all of this Hpricot experience I came up with a cheat sheet for my fellow developers at Sagebit and I am working on putting it up here as a PDF. It should be available soon.
Update: The Hpricot Cheat Sheet is now available!
Preview:

I’ve been reading a lot of books on web standards and the improvement of those standards. The rapid pace at which the web has evolved has left a gaping hole in what should be a standardized medium. There are plenty of governing bodies to create standards, but the sheer volume of the content on the web, the ease at which just about anyone can publish on the web, and the amount of new content added daily, standards have been forgotten.
In recent years there have been many advocates for web standards, both on the web and in published form. Two of the most notable, and the authors books I have been reading, are Jeffry Zeldman (Designing with Web Standards, http://www.zeldman.com/dwws/) and Andy Clarke (Transcending CSS, http://transcendingcss.com/). These authors promote web standards through visible design and the use of semantic markup. Standardization of the design creates clearer content and communication through that content. Standardization of the markup creates a web that provides a consistent experience for every user on every browser and is more usable by accessibility devices such as screen readers.
Most of the major web browsers, Mozilla Firefox, Apple Safari and Opera, adhere to web supremely well despite a few inconsistency between each other. Most of the major browser have their own forms of supporting web standards. Mozilla houses many resources on its Developer Center (http://developer.mozilla.org/En) with articles ranging from standards to accessibility. Opera also has a section of its website devoted to evangelizing web standards through curriculum. (http://www.opera.com/wsc/) Although Opera’s was still under development, there is already plenty of promising material available.
Why standards? The web was created to communicate and communication without standardization is just a bunch of white noise. As standards gradually improve so will the quality of content and communication on the web.
A key element of Cartabuzz’s design was to display event locations clearly on a custom map. After weighing our options, we decided to use the Google Maps API to achieve this goal. Two rails plugins were also integrated to make the Google Map utilization easier:
- YM4R/GM, which wraps the Google Maps API’s objects and methods in Ruby calls for easier Rails integration (http://ym4r.rubyforge.org/)
- GeoKit, which assisted with geocoding coordinates for venues, as well as assisting with distance calculations (http://geokit.rubyforge.org/)
This setup allowed us to build an effective Cartabuzz prototype without heavy JavaScript manipulation. However, we soon learned that for the more complex Cartabuzz functionality, we would have to dive deep into the JavaScript and get our hands dirty. One of the most difficult challenges I faced with this portion of the project came with associating the markers on the map with their respective event links at the bottom of the page. Since we wanted to let users see the events on the map one day at a time, we needed to retrieve the events from the database and store them in a two-dimensional array. However, this made it extremely difficult to store every day’s events in the same data structure. To solve this problem, I divided up the marker allocation into separate Marker Group objects, one for each day of the week, so that we could associate certain event markers with specific days while still being able to reference specific markers by id number.
Another large issue I faced was with handling the marker and link highlighting effects, as well as rendering the event information overlay. This functionality required quite a bit of editing of the YM4R/GM plugin’s code, as we had to modify the existing Marker Group object to better create JavaScript event triggers from Ruby data. Several parts of this functionality required some fairly complex code manipulation to perform seemingly simple tasks due to the issues of using direct Ruby data within the Google Maps’ JavaScript engine. In the end, however, this work paid off. Not only were the results beneficial to the layout and functionality of Cartabuzz, but I walked away with a greater knowledge of integrating JavaScript into Rails while learning some of its limitations.
We recently launched the second beta version Cartabuzz with a shiny new and interactive interface!
Cartabuzz.com is a new way to browse and explore events in Indianapolis. The goal of Cartabuzz is to make it fun and easy to find things to do in Indianapolis. Even if you already know what you’re doing this weekend, you might find something else to do before or after your weekend plans. We’ve gathered up a whole truck load of events and loaded them in Cartabuzz, so you can start finding new events today.
We’ve been working hard to integrate all the new features into the new version of Cartabuzz. Check out just a few of the features in Beta 2:
- A Large map to move around and view all the events in the Indianapolis area.
- Customized map information pop ups to get the information you need in order to attend an event.
- Advanced searching and filtering features to narrow down the choices of events.
- An interactive event browser to see all the events for each of the next seven days.
Below is a sample of the promo email that is being sent out to a select audience for the beta launch:

We would love to hear what you think of Cartabuzz. Go to http://www.cartabuzz.com, try it out and click the ‘feedback’ link at the top of the page to tell us what you think. Give us some good suggestions and you can help make the next version of Cartabuzz even better!
The new Sagebit blog is live at http://blog.sagebit.com and ready for action. If you want to learn about Sagebit and our Rails developing business, cruise over to http://www.sagebit.com. This blog is the home of tech. Look for all sorts of exciting posts here on our technical prowess!