Rails 1.1 Reference sheet

Courtesy of InVisible, here is an exhaustive Ruby on Rails 1.1 Cheat Sheet. I’ve added a copy of it here so I know where to find it: Rails 1.1 Cheat Sheet. There is also a PDF version available.

It covers everything from the basics, generators, scaffolds, models, controllers, views (including AJAX), and configuration.

Check it out!

Arghhhhh! The path to ruby lib is wrong!

nanoRAILS was down for the past 12h because of a setup change on my host on DreamHost.

Suddenly, the link /usr/local/lib/ruby was changed to point to an incorrect location, so instead of having the ruby libraries under /usr/local/lib/ruby/1.8, they would effectively be under /usr/local/lib/ruby/ruby/1.8 :(

Suffice it to say that things don’t work too well after that.

Running dispatch.fgci by hand revealed that “require pathname” fails. Hmmm, that’s not supposed to happen! That when I realized the above mentioned link had been changed just a few hours before.

After tinkering some more, and trying a few options, I managed to put a kludge together till the link is put back in the right place.

In the public directory, I created a myruby script:

#!/bin/bash
export RUBYLIB=/usr/local/lib/ruby/ruby/1.8/:/usr/local/lib/ruby/ruby/1.8/i386-linux/
/usr/bin/ruby $*

Make sure that script is executable (chmod +x myruby)

then in dispatch.fcgi, I replaced the first line with:

#!/usr/bin/env [PATH TO YOUR RAILS APP]/public/myruby

Of course, this will likely break once the link is restored to its correct value.

You’ve got to love using a shared host!

Update: ruby setup is back to normal now. At least I learned something in the process.
Everyone that was inconvenienced by this outage, please accept my apologies.

Caching ads from TextLinkAds in rails

In the first part, I explained how you could
Display ads from TextLinkAds in a rails application.
This created the basis for today’s addition: caching.

You know that the ads won’t change that often, and saving your bandwith and CPU cycle (and TextLinkAds too) is not too much to ask.

One way to achieve that is to use the fragment cache provided by Ruby on Rails. It does not however provide expiration dates. To add expiration, you can use 2 related elements, one for storing the expiration, one to store the actual data.

Firt you need to generate the names of the 2 keys:

def fragment_key(name)
  return “TLA/TIME/#{name}”, “TLA/DATA/#{name}”
end

and here, the logic to check whether the cache is present, and has not expired.

def content
  url = “http://www.text-link-ads.com/xml.php?inventory_key=”+@sb_config[‘key’]+”&referer=”+CGI::escape(@request.env[‘REQUEST_URI’])
  agent = “&user_agent=”+CGI::escape(@request.env[‘HTTP_USER_AGENT’])
  url_time, url_data = fragment_key(url)

  #is it time to update the cache?
  time = read_fragment(url_time)
  if (time == nil) || (time.to_time < Time.now)
    @links = request(url+agent) rescue nil
    #if we can get the latest, then update the cache
    if @links != nil
      expire_fragment(url_time)
      expire_fragment(url_data)
      write_fragment(url_time, Time.now+6.hour)
      write_fragment(url_data, @links)
    else
      #otherwise try again in 1 hour
      write_fragment(url_time, Time.now+1.hour)
      @links = read_fragment(url_data)
    end
  else
    #use the cache
    @links = read_fragment(url_data)
  end
end

In case the request to TextLinkAds fails (@links is nil), for whatever reason, you keep the cache for one extra hour till you make an other attempt.

And to make the code complete, here are the needed files to include and other needed helper functions:

require 'net/http'
require 'cgi'

def request(url)
  XmlSimple.xml_in(http_get(url))
end

# Does an HTTP GET on a given URL and returns the response body
def http_get(url)
  Net::HTTP.get_response(URI.parse(url)).body.to_s
end

So this takes care of caching the calls to TextLinkAds. You may not be done, though. Depending on the app you use, and its caching strategy, you may have another problem to solve. Your app may be caching your pages and actions, which may cause your links from TextLinkAds never to be updated. One solution is to use an approach similar to the one used by typo as described by Scott Laird and use caches_action_with_params from *scottstuff*.

This can wrap any method in your controller, and provide you the ability to control the longevity of your application’s cache simply by setting the lifetime value in the response:

response.lifetime = 6.hour

So for an application like typo, the code would be:

def content
  response.lifetime = 6.hour
  url = "http://www.text-link-ads.com/xml.php?inventory_key="+@sb_config['key']+"&referer="+CGI::escape(@request.env['REQUEST_URI'])
  agent = "&user_agent="+CGI::escape(@request.env['HTTP_USER_AGENT'])
  url_time, url_data = fragment_key(url)

  #is it time to update the cache?
  time = read_fragment(url_time)
  if (time == nil) || (time.to_time < Time.now)
    @links = request(url+agent) rescue nil
    #if we can get the latest, then update the cache
    if @links != nil
      expire_fragment(url_time)
      expire_fragment(url_data)
      write_fragment(url_time, Time.now+6.hour)
      write_fragment(url_data, @links)
    else
      #otherwise try again in 1 hour
      write_fragment(url_time, Time.now+1.hour)
      @links = read_fragment(url_data)
    end
  else
    #use the cache
    @links = read_fragment(url_data)
  end
end

As time permits, I’ll be posting my sidebar plugin for typo to provide a nice UI to set your TextLinkAds account and referral id.

Text Link Ads

readable output in rails script/breakpointer

After hours spent in breakpointer struggling to make sense of the output, I figured there had to be a better way to look at a stack trace than what the default output provides:

irb(ArticlesController):007:0> caller
=> [&#8220;./vendor/rails/railties/lib/breakpoint.rb:512:in `breakpoint&#8217;&#8221;, &#8220;./vendor/rails/railties/lib/breakpoint.rb:512:in `breakpoint&#8217;&#8221;, &#8220;./vendor/rails/actionpack/lib/action_controller/caching.rb:510:in `cache_sweeper&#8217;&#8221;, &#8220;./app/controllers/articles_controller.rb:7&#8221;, &#8230;]

Well, after some research, I found at least 4! And they work for any data structure, not just for stack traces, but I’m a pretty happy camper just with cleaner stack traces!

Solution #1
Building on Using the standard output in breakpointer, you can use each to get a more decent output.

caller.each { |x|  client.puts x }

which returns:

./vendor/rails/railties/lib/breakpoint.rb:512:in `breakpoint&#8217;
./vendor/rails/railties/lib/breakpoint.rb:512:in `breakpoint&#8217;
./vendor/rails/actionpack/lib/action_controller/caching.rb:510:in `cache_sweeper&#8217;
&#8230;

Solution #2
Use PrettyPrint

client.require &#8216;pp&#8217;
client.pp caller

Solution #3
Use YAML

client.require &#8216;yaml&#8217;
client.y caller

Solution #4
Use to_yaml

client.puts caller.to_yaml

These methods can also be used to display any complex data.

Try it on the request object for example.

To avoid having to type the require each time, add to .irbrc:

require &#8216;yaml&#8217;
require &#8216;pp&#8217;

Using the standard output in script/breakpointer

When you use script/breakpointer, once you have stopped in irb, if you try using print, puts or some other way to display something, your ouput goes to your main rails output, not to irb, which is not quite convenient.

First, it took me a while to realize where the output was in fact going. I guessed I was not too quick on that one.

Second, even knowing where to look, I did not find this solution very satisfying.

It turns out there is a solution. the client variable can help you use the right output

client.print &#8220;hello\n&#8221;

will output:

hello
=> nil

Works the same for puts.

Displaying ads from TextLinkAds in a rails application

Once my application with TextLinkAds was approved, I looked for a sample code to make it work in typo, or more generally in Ruby on Rails. TextLinkAds did not provide any, and a quick search in google did not return anything.

So I took their php example and came up with these snippets.

In your controller:

require &#8216;net/http&#8217;
require &#8216;cgi&#8217;

def content
  url = &#8220;http://www.text-link-ads.com/xml.php?inventory_key=&#8221;+TEXTLINKADS KEY+&#8221;&referer=&#8221;+CGI::escape(@request.env[&#8216;REQUEST_URI&#8217;])+&#8221;&user_agent=&#8221;+CGI::escape(@request.env[&#8216;HTTP_USER_AGENT&#8217;])
  @links = request(url) rescue nil
end

def request(url)
  XmlSimple.xml_in(http_get(url))
end

def http_get(url)
  Net::HTTP.get_response(URI.parse(url)).body.to_s
end

And in your view (rhtml), you just need to add:

<% if @links != nil %>
    <% if (@links != nil)&&(@links["Link"] != nil) %>
        <% for link in @links["Link"] -%>
            <li><%= link['BeforeText'][0] -%> <
                a href="<%= link['URL'][0] -%>&#8221;><%= link['Text'][0] -%></a> <%= link['AfterText'][0] -%> </li>
        <% end -%>
    <% end -%>
<% else %>
    Advertise here!
<% end -%>

To make the above look right with markdown, I had to cut the < a > element in between. When pasting this, remove the carriage return. If someone has a better idea on how to prevent the < a > element from being interpreted as a link even in a code block, please let me know!

Based on the example, it is fine to cache the result, so I’ll be adding that later tonight. As soon as I get caching up and running, I’ll also post the typo sidebar plugin

Text Link Ads

5/4/06 update: I tweaked the code to account for the no links at all case. TextLinkAds starts with a test link that they later remove, and my code broke. I replaced:

<% if @links != nil %>

by

<% if (@links != nil)&&(@links["Link"] != nil) %>

Scale your database

There is a very good ongoing series on O’Reilly Radar called Database War Stories. Or in other words, how various people with a lot of users and page views address their database scalabitity issues. It ranges from using no database at all and using flat files, to using a cluster of databases (with one master, and several slaves).
If you ever hope to see your application reach the stratosphere, it is worth a read. Scalability is something to keep in mind, but please, don’t over engineer your application from the get go. Focus on features and usability first, and make it more scalable when you need to. Knowing what it takes might help make your life easier when you get there.

The first 5 posts include stories about:

Of course the, database is only one dimension of scalability, but if you don’t get that one right, you might as well go home.

in News | 175 Words

Tracks: Getting things done

Yesterday, I came across a cool rails project: Tracks and it got me very excited. I spent 30 minutes to install it, and started entering some data. And the best part, I already completed 2 actions!
Tracks is a web based application to help you in Getting Things DONE: The Art of Stress-Free Productivity, a very effective method by David Allen. David’s approach is based on a few simple tenets: chanelling all inputs to as few buckets as possible, figuring out what the next action is for each project, deciding what to do next based on energy level, time available and priority… David developed this method based on his years as a consultant and anyone can approach it and implement it effectively with a little discipline.
Using Tracks can help you Get Things DONE! I had been trying to use BaseCamp so far, but I like Tracks approach better. With basecamp, I can’t figure out easily what to do next. Tracks presents you all the actions to be done on all projects sorted by due date.
Don’t get me wrong, BaseCamp is a very nice tool and comparing the 2 is not really fair for either. I had been trying to use basecamp to do what Tracks is designed to do.

The project is still a bit rough and I didn’t see much installation instructions, and it could be I didn’t look hard enough. I got the source code from the project subversion, and after after a few attempts, here’s what I did on Kubuntu 5.10.

svn co &#8211;username=guest http://www.rousette.org.uk/svn/tracks-repos/tags/tracks-1.041 tracks-local/

password is “guest”

create a database (tracks)

Create environment.rb and database.yml from the templates provided:

cp environment.rb.tmpl environment.rb
cp database.yml.tmpl database.yml

Edit database.yml (set correct user, password if you used tracks). I did not need to modify environment.rb.

Create a log directory

mkdir log

Remove the updates from 2adduser_id.rb

#    execute &#8220;UPDATE &#8216;contexts&#8217; SET &#8216;user_id&#8217; = 1;&#8221;
#    execute &#8220;UPDATE &#8216;projects&#8217; SET &#8216;user_id&#8217; = 1;&#8221;
#    execute &#8220;UPDATE &#8216;todos&#8217; SET &#8216;user_id&#8217; = 1;&#8221;

run:

rake migrate

check the path to ruby in script/server
And finally run:

script/server

Then first, create a user: http://localhost:3000/signup.
Then you can start using it: http://localhost:3000

Selecting a rails hosting service

Is there is one thing you could agree with, it is that there are many hosting options for your Ruby on Rail application. And this is a good thing for you. This is good because this means that there are a lot of companies competing for your business.

But it can be easy to get lost in this multitude of offers. So you need to define a selection process before you begin. Write down the criteria that you find important. And as you do your research, that list may change, and that’s ok. This is only a starting point. If you change that list too much, this may be warning flag that you are getting influenced too much but what you are reading.

To help you get started, here’s the list I used when selecting a hosting service:

rails support: that’s the main reason you are looking for a hosting solution. So get the best you can get! This one almost trumps all the others. Ideally you want to find someone that has had quite a bit of experience with rails, and has had a chance to fine tune their systems over time. You also want to make sure they offer more than just plain CGI, something like FastCGI, or FCGI, or even offer LightTPD support. If you don’t have to set it up, any of these will do. In my experience, it is not so important that they provide the latest gems and rails versions as you are better off freezing your gems.

Subversion support: to use Capistrano, this is something which is going to be helpful. You may be able to get CVS working, but subversion is a much better solution overall.

Capistrano support: with ssh and svn, you should be good
Price: Price matters, but most offerings are in the same ballpark, making this secondary. Get something you are comfortable with.

Disk space: you need enough to get your application running. If you envision something with a lots of graphics, sounds or movies, then you will need a lot.

Bandwidth: same as for disk space. You can start small to keep the price down, and most hosting companies will let you upgrade to their next offering, which generally gives you more bandwith, and only charge you the price difference.

Number of domains: how many domains do you really need? 5 to 10 should be more than you need. The thing you really need is the ability to have real domains, without some sort of redirection or frame redirecting to a subdirectory to your main domain.

Number of subdomains: I would not settle for less than an unlimited domain.
Number of databases: you only generally need just 1 or 2 for your application, but why you be charged by the database? They already limit the disk space and the bandwidth. So you’ll get the more serious ones by selecting one that doesn’t limit you.

Backup: once your application reaches production state, you need backups (trust me on that one, you don’t want to get caught without a backup). Site5 has a very nice feature where you get to restore your onw backups whenever you want.

Statistics: you need at least decent statistics. although you may feel the need to use a specialized service, such as Google Analytics, SiteMeter, or more analytics options which will give you a lot more details that what most hosting services give you.

SSH access: this one is a must. To run Capistrano, you need this. Plus this generally comes with ftp access, you get to run rails by hand if necessary, etc.
Email: that’s a no brainer, and I would just look for a good spam solution to go with that.

Excellent uptime: 99.9… or so. You can only go with what the vendor claims. If they are willing to back it with some refund, then they really mean it.
Moneyback: all the serious hosting company will let you try it for at least a month. To weed out the less serious, insist on 60 days or more.

Once you’ve defined your list of criteria, do some research, use google, ask your friends, look for what other people are using.

Create a spreadsheet where you list the various plans for each hosting company with some notes on each criteria.

Very quickly, the top 2 or 3 will start to emerge. Then you can dig a bit deeper, look for what others are saying, look to see if there are a lot of people complaining. For the price, you may even want to give your top 2 or 3 a test drive and see for yourself.

Good luck!

AjaxScaffold 3.0.0 released

He quickly released 2 updates so the big kinks are now out of the way. Thank you Richard for your hard work.

There is one bit of bad news though, you can forget about migrating from previous versions, but given the improvements, I think this is only a small price to pay.

For downloads, tutorials, documentation and a live demo, see Ajax Scaffold Generator.