Posts tagged rails

Feb 23, 2010

Setting up watchr and Rails

ruby rails watchr autotest | comments

Autotest is a great idea. When it worked for me, I loved it. But I hardly ever used it. Our complicated codebase choked on it - something to do with accounts as subdomains or double-loading of test_helper when running the test suite or some such. Frankly, I don’t remember the details, but I do remember the multiple two-hour wild goose chases to try to get the lovely software to work for me. Unfortunately I wasn’t up to the task.

And the Growl integration problems? Oi!

So this afternoon I decided to give watchr a try. I wasn’t hopeful and time-boxed myself at an hour. No rat hole for me, no sir.

Imagine my surprise when 45 minutes later I not only had watchr working, but I placed it just so in my environment. I could use my script on any Rails app on my system with full growl notification and more!

Automatic testing with Rails

The steps for me to setup watchr were fairly straightforward. On the command line (your symlink will vary, natch):

gem install watchr
ln -s /Users/barry/.gem/ruby/1.8/gems/watchr-0.6/bin/watchr /usr/local/bin/watchr

I am using this Rails watchr script - I haven’t modified it as of yet. I placed it in ~/.watchr/rails.rb.

I placed the following two images into ~/.watchr_images/passed.png and ~/.watchr_images/failed.png respectively:

Rails tests passed

Rails tests failed

To run watchr on my Rails app, from the code directory:

watchr ~/.watchr/rails.rb

To make this less super-annoying I set a bash alias:

alias watch="watchr ~/.watchr/rails.rb"  # default is Rails cause that's my most frequent workspace

So tomorrow morning I’ll open a terminal window and type:

watch

Life is good!

(My watchr links at Delicious.)


Jan 19, 2009

Rails date calculations could stand some timezone love

programming rails ruby | comments

New Rails handles a lot of timezone stuff for you. Set the appropriate time zone for the request and get an object from the DB, it’s created_at date will be translated from UTC to the request’s time zone.

Rails doesn’t do anything with the Ruby enhancements that create time objects from dates. Like:

Date.today.end_of_day

That’ll be in the server’s time zone. Ick.

I needed to find the beginning of a day as related to the request’s timezone. I moved the fix into some date extensions:

class ::Date
  def beginning_of_day_in_zone
    Time.zone.parse(self.to_s)
  end
  alias_method :at_beginning_of_day_in_zone, :beginning_of_day_in_zone
  alias_method :midnight_in_zone, :beginning_of_day_in_zone
  alias_method :at_midnight_in_zone, :beginning_of_day_in_zone

  def end_of_day_in_zone
    Time.zone.parse((self+1).to_s) - 1
  end
end

So now we have:

Time.zone = "Auckland"
=> "Auckland"
> Date.today.beginning_of_day
=> Tue Dec 09 00:00:00 -0600 2008
> Date.today.beginning_of_day_in_zone
=> Tue, 09 Dec 2008 00:00:00 NZDT +13:00

Realistically, I think Rails could be improved in this area. Or maybe I’m missing out on a better way to take a date object and make it zone-aware for generating related times. I spent more than an hour reading through the Rails date and time extensions and realized I need to keep my timezone pain relegated to the work week. For the time being, the above is a nice crutch for my current needs.


Nov 11, 2008

Announcing time warp ruby gem

change time gem rails ruby time manipulation time warp | comments

When writing tests, it is often desirable to bend time to test limits and edges of the day. It is especially useful to warp time to test results across the timezones of the world. Manipulating time is also useful to assure a day of the week, month or year every time the test runs.

Some may say “Why not just mock Time#now?” I see the point, but I find mocking around with baseline Ruby classes to be asking for trouble. Eventually unusual behavior will rear its head and a day will be lost debugging tests - the most excruciating debugging one can be subjected to.

For all of your time manipulation needs, give time warp a try in gem or plugin form.


Oct 16, 2008

Fading flash message

flash message programming rails ruby | comments

Rails apps love flash messages. Little notes providing information, confirmation or warnings to the user. Typically implemented in a partial like so:

<% if flash[:warning] -%>
   <div id='warning'><%= flash[:warning] -%></div>
<% end -%>
<% if flash[:notice] -%>
  <div id='notice'><%= flash[:notice] -%></div>
<% end -%>

There are many cases where the message does not need to stick around for long. Consider a page with lots of AJAX interactions. Perhaps the user sends a message, which causes a page reload with a flash confirmation note (e.g. “You’re message was sent.”). After this the user will remain on the page for a relatively long time, maybe inline editing some properties or settings with AJAX tools.

It sure would be nice if that flash message would fade into the sunset after a few seconds and give back its valuable real estate, yes? Especially without forcing every flash message to disappear like Bobby Fischer.

Ask and receive, my friends. Introducing the fading_flash_message method, to be added to your nearest ApplicationController:

def fading_flash_message(text, seconds=3)
  text +
    <<-EOJS
      <script type='text/javascript'>
        Event.observe(window, 'load',function() { 
          setTimeout(function() {
            message_id = $('notice') ? 'notice' : 'warning';
            new Effect.Fade(message_id);
          }, #{seconds*1000});
        }, false);
      </script>
    EOJS
end

Setting a fading flash message in your controller is simple:

flash[:notice] = fading_flash_message("Thank you for your message.", 5)

This is change we can believe in, my friends.

Update

For Rails 3, this still works with a simple inclusion of the RawOutputHelper.

include ActionView::Helpers::RawOutputHelper
def fading_flash_message(text, seconds=3)
  raw text +
    <<-EOJS
      <script type='text/javascript'>
        Event.observe(window, 'load',function() { 
          setTimeout(function() {
            message_id = $('notice') ? 'notice' : 'warning';
            new Effect.Fade(message_id);
          }, #{seconds*1000});
        }, false);
      </script>
    EOJS
end

Aug 29, 2008

Windy City Rails

conference rails ruby | comments

I am all registered for Windy City Rails, taking place in Chicago on September 20th. Looking forward to a shorter conference, along with an interesting drive with fellow Minnesota Rubyists. Come join us - only $99!


Aug 21, 2008

Blogiversaire

programming rails ruby | comments

Four years baby. Soon the blog will be toting a lunch pail and school bag, off to decades of education. Next thing I know, my little baby will be married and have little blogs of its own. Blog, you grow up so fast!

Top visited blog posts written in the past year:

As you can see, the popularity of this blog is directly related to what problems I’ve had with Ruby on Rails and people who search Google for the same issues. This is kind of unfortunate in some ways. It makes the blog pretty much narrative-free. But I’m still happy to have helped those who needed it.

While 2008‘s posts have been much more rare, I think there are some gems in there. Going forward, I hope to include a mix of posts explaining a solved problem, displaying a new technique, and generally talking about the unique work life I live with day-to-day.


Jul 22, 2008

Post Redirect Get in Rails

post/redirect/get rails ruby | comments

Post St.
 
Photo by Terry Bain

Post/Redirect/Get (PRG) is a web application design pattern used to supply users with nice, GET-generated results pages that bookmark and reload with ease.

Say you have a results page with a filtering form at the top. The user might alter filtering options, and submit a form to winnow down her results. This is a POST, meaning params will be hidden from the user (not in the URL), making direct bookmarks to the filtered results impossible. Also, reloading the page will result in a “POSTDATA” warning message (“Do you want to resubmit POST data or would you rather we do a hurkey-jerky dance to confuse you?”) to the user. These are not things people like to deal with. Post/Redirect/Get says that your application should accept the POST command, and redirect to the results page using a GET request.

This is really quite simple to implement in Rails. Take this example action filter for an expense report controller, reduced to its bare essentials:

class ExpenseReportsController < ApplicationController
  def filtered
    redirect_to fitered_expense_report_path(params) and return if request.post?
    
    # Actual action work here.
  end
end

Very easy - the trick is really knowing the pattern more than anything. There has been some discussion on adapting this to deal with validation failures. In my experience, I’ve only made use of this pattern in non-RESTful controllers. You are sure to do better with it than I.


Jul 15, 2008

Fixing slow rake on Leopard

mysql rails rake ruby ruby on rails | comments

Hay Rake Third Version
 
Photo by JBAT

Update: I highly recommend going with Ruby Enterprise Edition and Evan Weaver's Ruby GC settings for much improved Ruby speed.

In the past few months, as a result of my clumsiness, I’ve been working on a new, Leopard-enabled MacBook. When replacing my wet and dying Tiger MacBook of yore, my one hope was that my daily executions of rake to test Harvest would execute a little faster. A 20% increase in processor speed doesn’t buy one a whole lot when web programming. The one place I figured I’d see a bump is the constant processor use of rake.

Wrong. So, so, wrong.

After moving to a new MacBook with Leopard installed, I experienced a test suite that ran 2-3 times slower than on my old machine. This became the difference between testing frequently and hardly at all; the difference between using and not using autotest. Pain to the max.

This post is going to get long, so I’m going to reveal now. For me, the issue was resolved by leaving the canonical Hivelogic world and reverting to the default Leopard installation of Ruby. Test speed returned to better-than-normal, and all at the price of only 6 hours of troubleshooting!

MySQL: Like shooting fish in a Superior-sized barrel

As always, my first suspicion was MySQL. I looked through my local Rails logs for particularly slow calls into MySQL. The initial thought was that a few bad-apple tests were not tuned very well for my environment. What I found was everything was slow and there were too many noticeably poor speeds to point to a few SQL calls as the culprits.

Next I compared my my.cnf file to my compadre‘s. I noticed no major smells in my file. Since I’m a DB dummy, more important was Dee’s estimation that indeed my configuration file looked alright. We even went so far as comparing MySQL variables from within the MySQL shell:

mysql> show variables;

Finally, I upgraded MySQL from 5.0.51 to 5.0.51b and reinstalled the ruby-mysql gem. No dice.

Sanity check: Benchmark the MacBook

Dee suggested I verify that my new MacBook itself wasn’t a lemon. I was doubtful since I’d noticed no other areas where it performed worse than its predecessor. Still, this was a great place to regroup. Benchmarking each MacBook put my mind in the right place to finish off my troubleshooting and uncover my problem.

I used Xbench to compare the general performance of my new and old MacBooks. Benchmark results favored the new machine everywhere except OpenGL. After reading the FAQ, it’s pretty clear OpenGL is a false positive for the old MacBook.

Rails: A general comparison between two machines

So I knew Rails was running slow when hitting the DB, but what about all by itself? I simply ran rake environment on both laptops and took a mental count. The command took ~3 seconds on the old machine and 6-7 seconds on the new one.

This was really enough, but I did run some model finders in each environment as a sort of sanity check. Performance results were in line with everything you’ve read so far.

Ruby: ActiveRecord-less and slow as ever

To hit the real meat-and-potatoes, I executed some Ruby-only code on both systems, benchmarking the whole way. Old Tiger:

$ ruby script/performance/benchmarker "(1..100).inject(1){|sum, n| sum*n}" 
            user     system      total        real
#1      0.000000   0.000000   0.000000 (  0.000217)

New Leopard:

$ ruby script/performance/benchmarker "(1..100).inject(1){|sum, n| sum*n}" 
            user     system      total        real
#1      0.000000   0.000000   0.000000 (  0.001347)

Over six times slower. New shit has come to light!

Sanity check II: Another system test

I wanted to run something from the command line that proved the new hotness was outperforming the old hoopty. Enter a little shell script built to copy an empty file to and from a folder 10,000 times:

#!/bin/sh
echo "start at `date +%s`" 
touch ./file.txt
mkdir ./fileholder

LIMIT=1000

for ((a=1; a <= LIMIT ; a++))
do
  mv ./file.txt fileholder/
  mv ./fileholder/file.txt ./
done

rm ./file.txt
rm -rf ./fileholder

echo "end at `date +%s`" 
exit 0

Rejoice! The new machine took 32 seconds to execute. The old one executed in 78 seconds. The winnowing process was imperfect, but I believe a winner has been crowned: Ruby.

Ruby: From source to simple

I pwnd Ruby
 
Photo by tychay

Both machines in question were on Ruby 1.8.6. The new one on patchlevel 114, the old one on 0. I attempted to install Ruby from source for patchlevel 230 (ACK!) and 111. No rake performance improvements were achieved. I also own a Leopard Mac Mini, installed from the Hivelogic instructions, and experienced the same rake downfalls (Sanity check III). Time to try Leopard’s default Ruby (patchlevel 114).

I did not want to remove /usr/local/bin from my path because I have other wonderful things installed there. Advisable or not, I simply renamed key binaries:

mv /usr/local/bin/ruby /usr/local/bin/ruby.bak
mv /usr/local/bin/rake /usr/local/bin/rake.bak
mv /usr/local/bin/irb /usr/local/bin/irb.bak

From there, all my gems needed reinstalled. gem install failed on my first try, but worked thereafter. The ruby-mysql gem had special needs (assuming a Hivelogic-style install of MySQL), which were addressed with:

sudo gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

rake clean. Barry happy.

I can’t say I’m comfortable browsing my filesystem for gem source like I was with /usr/local, but I imagine that will come with time. My suspicion is the Hivelogic instructions can still work in Leopard given the appropriate compilation switches. I’m not the person to provide such information - perhaps someone already has?


Jun 01, 2008

Presentation: an audience perspective

rails railsconf railsconf08 RailsConf RailsConf ‘08 Rails | comments

Baked NYC
 

This weekend I attended RailsConf. This was my first multi-day conference. It was a great experience that I’m sure to repeat over the coming years. Met a lot of great Rails developers, working on interesting and disparate projects. Met a good number of Harvest users who spoke to me using words like “enjoy,” “love,” and, most surprisingly, “famous.” Even met people doing Important Stuff (tm) who didn’t particularly care to hear about my story.

Watching speaker after speaker is terribly motivating. Soon the realization that this blog has pretty well been dormant in 2008 came to mind. The realization that I’ve not prepared a proper presentation…ever…entered my thoughts. As I sat in sessions, I found myself, with a wide sliver of irony, writing down presentation techniques that pleased and bothered me.

Humor

You have to include humor in your talk. Most presenters are aware of this. However, many presenters front-load their humor. It’s difficult to lace the entire flow of information with engaging humor, but this is one of the most outstanding ways to provide a positive experience for the audience - one that causes them to pursue the topic after the fact.

In the case of technical talks, one must be careful not to make the humor the focus. But generally speaking, presenters tend to err on the opposite end of the spectrum.

A consistent metaphor

Several sessions included an interesting, nerdy metaphor. Don’t meticulously introduce the Star Wars comparison and then drop it for the rest of the presentation. Lace that damn B-wing throughout the slides.

Know your environment

Your super-sexy, light-on-dark TextMate theme is most likely going to cause the audience fits. They will yell at you, especially if it is the cranky third day.

Greater than 15 lines of code is unlikely to be readable by the audience. Know how to zoom or bigify your code or think of other creative ways around the problem.

Slide titles should be mid-screen or higher. Cool MTV banner titles along the bottom of the screen are likely difficult for most of the audience to read, save for the most ideal conference situations.

Unless the presentation calls for frequent interaction with your computer, stand up. Give yourself the air of authority and the confidence that you are qualified to share information with the group. Don’t pace, and get yourself some sleep the day before.

Timing

Don’t hope your talk will fit into the given time slot, know it will fit. Err on the side of too short, please. Don’t promise time for questions unless you’re certain you can deliver. Plan for interruptions (technical issues, in-presentation questions, rambling, etc). You will be refreshing and set yourself apart if you deliver a well-tuned, concise message.

Tell them what they want to hear

Or Pander to the crowd.

Or Tell them what they already know, in a new way.

Or Inspire them to pursue what you know they want to pursue.

Littering your presentation with known community mores will give you at least a knee-jerk positive reaction. The audience wants to laugh, nod, clap, and feel assured in their own choices. Be a catalyst.

Ideally your whole presentation shouldn’t be comprised of such a message. But if you don’t have anything nice to say, reflecting your audience is probably your safest option.

If all else fails, blow their minds

Announce a product, process, tuning, enhancement, iteration or whatever that carries along with it jaw-dropping statistics. The nice thing about this is you don’t have to necessarily give the product in question to anyone to prove your statements - at least not right away. Plan on delivering something within a few months, and deliver something within 50% of the improvements originally touted, or you will be blasted.

This talk can be combined with telling people what they want to hear to make a powerful concoction. It is workable to describe utopian worlds where downfalls are leveled with a Sim-City-like ease. Again, any improvements will be welcomed, and the army of supporters from announcement-time will do all of you defense for you when the rubber meets the road.

It’s not about you

Indeed, some speakers enjoy well-attended presentations due to their niche fame. Still, it is not about them. It is about what the speaker can do for me, the audience member. How do you help me to relate to you? How do you help me fit your perhaps only tangentially applicable message into my situation? How can you generalize the information you have for public consumption? How can you make it all about me?


May 28, 2008

RailsConf '08

rails railsconf railsconf08 RailsConf RailsConf '08 | comments

Just wanted to drop a note in my blog, here, that I will be attending RailsConf from Friday through Sunday. If any lurkers out there are gonna be in attendance, do drop me a note. Let’s meet each other!

If you want to stay up-to-date on any Barry-meets-RailsConf information, please check me out on Twitter.


Feb 28, 2008

Move server configuration files into your repository

capistrano rails ruby scm svn Ruby Rails SVN SCM Capistrano | comments

Dung repository
 
Photo by Chambo25

Are you a programmer? Do you hate any process that involves SSH’ing into a server and editing files directly in production? Would you like to get rid of this non-source controlled hackery? Damn right you would!

If you’re deploying an application to a server, get those app-specific configuration files in your source control system! I happen to be a Ruby on Rails programmer, so the two files I’m looking to control are the Apache and Mongrel configuration files. Here are two sample locations:

Maruku could not parse this XML/HTML: 
<pre>/usr/local/apache2/conf/apps/appname.conf
/etc/mongrel_cluster/appname.yml

Meat

Via terminal, browse into your local Rails app directory. Then, create a couple directories to store this configuration:

mkdir ./config/apache
mkdir ./config/mongrel

Then copy the configuration files you have sitting on your server into the local directory (I’m using SCP and assuming you know the rest). Again, locally:

scp bjhess@server_or_ip:/usr/local/apache2/conf/apps/appname.conf ./config/apache/
scp bjhess@server_or_ip:/etc/mongrel_cluster/appname.yml ./config/mongrel/

Potatoes

Now you’re all ready to commit these configuration repositories to your SVN/git/mercurial repository. But wait, you also want to actually use these versions of the configuration files in production, no? Well, let’s do it. Rename the original configuration files on the remote server:

mv /usr/local/apache2/conf/apps/appname.conf /usr/local/apache2/conf/apps/appname.conf.bak
mv /etc/mongrel_cluster/appname.yml /etc/mongrel_cluster/appname.yml.bak

Then simply update your deployment script to create symlinks from the expected configuration file location to the new location. I’m using Capistrano (version OLD), so adjust accordingly:

desc "Tasks to complete after code update"
task :after_update_code do
  #            LINK TARGET                                   LINK SOURCE
  run "ln -nfs #{current_release}/config/apache/appname.conf /usr/local/apache2/conf/apps/appname.conf"
  run "ln -nfs #{current_release}/config/mongrel/appname.yml /etc/mongrel_cluster/appname.yml"
end

Conclusion

This is great, isn’t it? The programmer in you loves having limitless history of configuration changes, not to mention the ability to use whatever local editor you choose. Wonderful day!

But what about the whole-server configuration files? Unless you commit to one app per server, I don’t think base Apache config files or server-level logrotate config files should be in a specific app’s repository. Perhaps a new repository could be setup to deal with these files? I imagine Capistrano could even be used for the bare-bones deployment.

Or maybe just backing up these general files is enough to keep your mind at ease. Just be sure to think about it. That’ll put you one step ahead of the rest

Update: Be sure to deal with symlinks upon rollbacks, something I just got burnt by:

desc "Tasks to complete after code rollback"
task :after_rollback do
  run "ln -nfs #{previous_release}/config/apache/appname.conf /usr/local/apache2/conf/apps/appname.conf"
end

Oct 29, 2007

World Clock Project

world clocks time rails | comments

Last week, the fellas at Iridesco and I put together a fun little Internet clock for your time-telling needs. It’s officially online and ready to give you the time of day in a world-conscious way.

Visit the World Clock Project.


May 26, 2007

When Rake fails but tests succeed

rails rake fixtures rails rake fixtures | comments

When testing Ruby on Rails, every so often you’ll find that rake fails in testing while running a test directly succeeds. How frustrating!

The crux of the problem is typically a missing fixture in the test class. What happens is that the data from your missing fixture is loaded in the test database, masking the problem when running a test individually. Since the order of operations on a rake test is clearly different than running a test singularly, there is a good chance that the data your test depends on simply is not loaded during the rake process. Unless you add that missing fixture, of course.

One more reason to learn the best methods of writing tests without fixtures.