String is a number?

Anton Jenkins | June 22, 2009

I’ve been fishing around to see if Ruby has any way of telling whether a String object contains a valid number. The is_a? method looked like it might be a winner for a little while…

1
2
3
4
5
>> 34.is_a?(Numeric)
=> true

>> "rah rah".is_a?(Numeric)
=> false

So far so good. But my number is going to be stored in a String, and is_a? doesn’t actually look at the value of the String, it just checks its type.

1
2
>> "34".is_a?(Numeric)
=> false

Ah. Fail. String isn’t a numerical class so even though it contains a numerical string, it’s always going to fail that test.

What about to_i?

I found to_i a little too clever for my needs…

1
2
3
4
5
6
7
8
9
>> "34".to_i
=> 34

# All good so far...

>> "34DFDF".to_i
=> 34

# Ah. Fail.

I don’t know why I typed 34DFDF. Sounds like a scary bra size….

Rails Forum to the rescue

Next I found a thread on railsforum.com which showed how to make an is_numeric? method and I decided to take that idea and extend the Object class to include this method on all objects. The idea being you could go :

1
2
3
4
5
6
7
8
>> 34.is_numeric?
=> true

>> "34".is_numeric?
=> true

>> "34DFDF".is_numeric?
=> false

That’s perfect, so let’s write it….

Writing an is_numeric? method

I’m going to extend the Object class with this method so that it’s available everywhere. I’m using this in a rails app so I wrote the following in lib/core_extensions/object.rb

1
2
3
4
5
6
7
8
9
# lib/core_extensions/object.rb

module CoreExtensions::Object
  def is_numeric?
    true if Float(self) rescue false
  end
end

Object.send(:include, CoreExtensions::Object)

What it’s doing is seeing if the Float class can instantiate an instance of itself with the value of object. If object can’t be parsed to a Float then it throws an exception. If an exception is rescued then we know the object can’t be numerical so we return false. Simples.

Now we just need to require our little extension at the end of our environment.rb:

1
2
3
# config/environment.rb

require 'core_extensions/object'

... and we’re ready to go!

1
2
3
4
5
6
7
8
>> 34.is_numeric?
=> true
>> "I'm not a number".is_numeric?
=> false
>> "34".is_numeric?
=> true
>> "34DFDF".is_numeric?
=> false

Perfect.

Why extend Object and not String?

I had a ponder about that and figured it wouldn’t hurt if is_numeric? was called on non strings. By extending Object I can do things such as 34.is_numeric? which isn’t too shoddy. And I’m guessing if something nasty happens the rescue should catch anything bad. But if you can think of a good case for making it a String only method then please feel free to comment.

Also if there’s a better way of checking for numericalness then please post that in the comments. I couldn’t find anything built in to Ruby but I must admit I found that surprising.

Just recently I’ve had to do a lot of work getting rails to play with a 15 year old Oracle database. Needless to say this database doesn’t follow the conventions we’ve all grown used to with rails. The table names are all over the place, the primary keys aren’t surrogate keys but actually have business meaning, composite keys which include date columns, crazy methods of generating primary keys instead of sequences….. if there’s a rails convention this thing doesn’t break then I’ve not found it yet!

However rails does provide methods for us to get it working with these legacy systems. Of course, if we were designing an application from scratch, we’d never need these techniques because we’d do it “the rails way” from the start. So I’m going to cover a couple of techniques which I’ve had to use in case you find yourself with the misfortune of having to marry rails to a pig!

Telling rails to use a different table and primary key

If we have a model named Student then rails convention dictates this model will map to a table called students and it will have a primary key called id. Well the real world isn’t always so accommodating. No problem…

1
2
3
4
class Student < ActiveRecord::Base
  set_table_name :student
  set_primary_key :s_stno
end

Composite keys

In this instance, the composite primary keys gem is your friend. Simply install…

1
sudo gem install composite_primary_keys

... and require in your environment.rb...

1
require 'composite_primary_keys'

Now you are ready to start supplying multiple keys in your models…

1
2
3
4
class CourseFee < ActiveRecord::Base
  set_table_name "course_avail"
  set_primary_keys :course_code, :course_date
end

You may notice that one of those composite keys is a date. This can cause you problems when you try and generate a url for an instance of this class because the date won’t be output in the correct format. So we need to override the to_param method to output the date in database format.

1
2
3
  def to_param
    "#{course_code},#{course_date.to_s(:db)}"
  end

Non standard primary key generation

This one was tricky! Now it wouldn’t be too hard if your legacy system uses a sequence to generate primary keys because you can just tell rails to use this sequence if it’s not named using the rails convention (which is tablename_seq).

1
2
3
class Student < ActiveRecord::Base
  set_sequence_name 'a_non_standard_sequence_name'
end

However you could find yourself in a nasty situation where the database doesn’t use a sequence for primary keys – it uses a value stored in a table instead. No problem you’re thinking to yourself, I’ll just use a before_create hook to populate the primary key? Nope, not going to work. The oracle_enhanced adapter will still go off and try to use a sequence called tablename_seq causing the whole house of cards to come crashing down. So we need to stop oracle_enhanced from looking for this sequence and instead tell it to generate the primary key some other way.

I stole the basis of this hack from the oracle_enhanced website and added my own twist to it to fit my circumstances. I doubt your scenario will exactly match mine (and I hope for your sake it doesn’t!), but you can use this as a starting point.

So…. the primary keys in my evil system are stored in a table called counter. There is only one row in this table and a column for each table you want a primary key for. Nasty. So I started off by generating a model for this table with a method to pull out a primary key…

1
2
3
4
5
6
7
8
9
10
class Counter < ActiveRecord::Base
  set_table_name :counter

  def self.next_primary_key(col)
    current_value = Counter.first.read_attribute(col)
    new_value = current_value + 1
    Counter.connection.execute("UPDATE counter SET #{col} = #{new_value}")
    new_value
  end
end

Now assuming there is a column in the counter table called student, I can pull a primary key out by calling:

1
Counter.next_primary_key('student')

This will increment the value in the column and return it. It’s a nasty way to generate primary keys but hey, I didn’t design this!

So now we can access these primary keys in a tidy way we need to get our Student model to use it for its primary keys. And this is where the fun starts – we need to monkey patch the oracle_enhanced adapter to use this table, but only when our table doesn’t have a sequence. To do this we create an initialiser in config/initializers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# config/initializers/oracle_enhanced.rb

ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
  alias_method :orig_next_sequence_value, :next_sequence_value

  def next_sequence_value(sequence_name)
    if sequence_name =~ /^counter-/
      # Strip the counter- part out of the string and pass the remainder to next_primary_key
      Counter.next_primary_key(sequence_name.match("counter-(.*$)")[1])
    else
      orig_next_sequence_value(sequence_name)
    end
  end
end

What this code does is check what the name of the model’s sequence is and if it starts with counter- it looks in the counter table for the primary key. So when we specify the following sequence name…

1
2
3
4
5
class Student < ActiveRecord::Base
  set_table_name :student
  set_primary_key :s_stno
  set_sequence_name 'counter-student'
end

... our little monkey patch will spot the counter- prefix, strip it out and make its primary key the result of a call to the following:

1
Counter.next_primary_key('student')

Perfect! It’s a little complicated but we’ve now got a flexible solution to cater for whatever crazy method of primary key generation our predecessors may have dreamt up. And the best part is it gracefully falls back to the default behaviour if the sequence name doesn’t start with counter-.

As I said before, the main guts of this hack (the monkey patching of oracle_enhanced) was written by Raimonds Simanovskis on the oracle_enhanced website. I merely souped it up a little with some regular expressions and adopted it to fit my particular use case.

Further reading

If you are wondering how to setup rails to talk to an Oracle database then you might be interested in my previous two part series on the subject which starts with this post

Flight Control tips

Anton Jenkins | May 19, 2009

I’ve been pottering around on this game for a good few weeks now so figured I may as well pass on a few things I’ve picked up….

1. Learn the entry points for the different aircraft

As the image shows, the different aircraft always appear from the same positions. If you learn these positions then you can stay one step ahead. If you see the little exclamation mark flashing in the spot a jumbo enters from then you know it’s a good idea to make sure it’s path to the runway is cleared in advance. Memorising these positions might only give you a second or two extra during the game but it can make all the difference.

2. Take the shortest possible route

There’s no point arcing nice curves on your flight paths – just get them to the start of the runway ASAP. If you have to cut some harsh turns around obstacles in order to do that then so be it.

If it looks like this is going to cause a massive pileup on the runway then just deal with it when it starts to unfold. Don’t make too many long winded routes to delay arrivals because you’d be surprised how many aircraft you can land in a small space by micromanaging the start of the runway.

3. Use the empty space over the runways

Usually the planes land pretty quickly so the majority of the runway is still open for you to use. A popular trick is to fly the planes up the runway the wrong way and then have them cut back on themselves to land. You might think that this will cause a head on crash with the planes coming in to land normally but usually these will land before they even reach the planes heading up the runway at them.

4. The faster it is, the higher you should prioritise it

If you can see that a jumbo and a helicopter are set for a collision course then take evasive manoeuvres with the helicopter and let the jumbo carry on unimpeded. Helicopters are so slow that you can usually just turn them around to get them out of the way and then, when the hazard has passed, draw a new flight path to the pad without them having deviated too far away from where they started.

You start moving a jumbo around to wait for a helicopter to pass and you’ll find yourself having to baby sit it much more than the helicopter. So move the helicopters out of the way instead. The same principle applies for all vehicles – allow the fastest to pass, move the slower one out of the way.

5. Landing the planes a little quicker

This one is a little hard to explain. Basically, when you draw a flight path to the runway, the planes will land quicker if you draw down the runway until it flashes rather than just holding your finger at the end of the runway and waiting for it to flash. Don’t believe me? Give it a go! You’ve probably already noticed that some planes land quickly whereas other planes seem to fly halfway down the runway before landing. Well this is most probably the reason.

6. Leave a little room around the start of the main runway for aborted landings

If you were to draw a straight line from the light aircraft and helicopters that come from the left of the screen to their final destinations then odds are it will bring them reasonably close to the main runway.

Arc these flight paths around the runway entrance a little to give yourself some breathing room. Quite often you will find a jumbo is going to reach the runway before a slower jet has landed and if you can’t slow the jumbo down because it has another one right behind it then you are going to need to clear the obstructing jet out of the way for a second. Arcing helicopters and light aircraft that enter from that left side helps give you a little room to play with.

7. Plan ahead when drawing around obstacles

One easy mistake to make is to draw a flight path around slower aircraft that will avoid them in their current positions. However, by the time your aircraft gets there the obstacles would have shifted! So think ahead and guess where the obstacles will eventually be and draw around that instead.

8. Try playing on a tabletop

This one is subjective but I find I quite often score higher if I play with the iPhone laying on a flat, stable surface. I guess it removes the variable of having to hold the device and will allow you to draw more accurate flight paths.

9. Don’t just rely on the proximity alerts

It’s easy to be lured into a false sense of security by the proximity alerts (you are playing with sound on I hope!). The alert will start when two aircraft get within a certain distance but it wont resound the alarm until they move sufficiently enough apart again. So if you’ve got two aircraft which are following very close flight paths then keep an eye on them. They could quite easily crash a good while after the alarm initially sounded and you won’t get another alarm after the first one.

10. Keep away from the edges

Obviously the edges are dangerous places to be so as a rule try to keep your aircraft away from them. However if you really must go near the edge make sure you do it near the middle of the edge. The reason being because only light aircraft and helicopters enter through the middle so it’s a little less risky. Check the first image at the top of the post to see where the different aircraft enter from.

11. Ram them into the helipad

The helipad is pretty forgiving. As long as you give each helicopter enough room at the edge then you can land several at the same time without them colliding. If you see two helicopters converging from different sides and they look like they will meet in the middle – don’t worry. They will both land before touching each other.

Got any more?

If you’ve got some killer tips then feel free to stick them in the comments.

Passing a hash of conditions to find in rails

Anton Jenkins | April 21, 2009

I just stumbled across a neat trick in ActiveRecord which could help make your code more readable:

1
2
3
User.find(:first, :conditions => { :forename => 'Anton',
                                   :surname => 'Jenkins',
                                   :age => some_value_from_a_form })

To me this is so much more readable than:

1
2
User.find(:first, :conditions => ["forename = ? AND surname = ? AND age = ?",
                                  'Anton', 'Jenkins', some_value_from_a_form])

I know which one I prefer. I can’t believe I’ve never seen anyone using hashes for conditions before! Have I had my head in the sand?

Let me know if there are any gotchas with this technique. Maybe there is a good reason I’ve not seen it used before.

Integrating Flickr into your rails website

Anton Jenkins | April 06, 2009

In this post I’m going to show you how I created the little Flickr stream you can see running down the right hand edge of this site.

Step 1: Get a Flickr API key

Visit this page and follow the instructions to get a key and write it down somewhere safe. Of course you are going to need a Flickr account to do this as well!

Step 2: Install the flickr_fu gem

This is the library that makes all the magic happen. Install the gem on your machine:

1
sudo gem install flickr-fu

Notice that’s a hyphen between ‘flickr’ and ‘fu’, not an underscore. And remember that you’ll need to install this gem on your production server as well, so make a note to do that.

Step 3: Tell your rails app to include the flickr_fu library

Just a quick visit to environment.rb to pull it in:

1
2
3
# config/environment.rb

require 'flickr_fu'

Underscore used this time. Very confusing!

Step 4: Configure the gem using a flickr.yml file

The best place to store this is in your config directory along with all your other config settings. Get that piece of paper handy that you wrote down your API key on because you will need it now:

1
2
3
4
5
# config/flickr.yml

key: "<paste your key in here>"
secret: "<paste your secret in here>"
token_cache: "token_cache.yml"

You won’t need the API key any more so you can eat that piece of paper.

Step 5: Have a play!

Right. Time to mess with it! What we are going to do now is fire up the rails console and retrieve some of your images. However the flickr APIs need to know your Flickr ID. For this we will use a website called idGettr

What you do is paste in the URL for your Flickr photostream and it spits out your Flickr ID which we can then use with the APIs. So for me I typed in http://www.flickr.com/photos/antonjenkins/ and it returned an ID of 12864272@N02.

Write this down somewhere, memorise it and then eat the piece of paper.

So lets have a play in the rails console:

1
2
3
4
# ./script/console

>> flickr = Flickr.new(File.join(RAILS_ROOT, 'config', 'flickr.yml'))
=> #<Flickr::Base:0x395d514 @token_cache="token_cache.yml", @api_secret="oooh, that's a secret!", @api_key="I could tell you but I'd have to kill you">

What we’ve done there is pointed flickr_fu to our little flickr.yml file and it’s given us back a connection to Flickr. So lets use it (and that Flickr ID we looked up a minute ago)....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>> photos = flickr.photos.search(:user_id => "12864272@N02")

# Boom! Loads of output!

>> photos.count
=> 90

# I seem to have an array of photos. Lets look at one...

>> photos[1].title
=> "Quack!"
>> photos[1].url
=> "http://farm4.static.flickr.com/3104/3303703736_ba4bea1dc5.jpg"

# Jackpot!

So we’re very happy now – we’re using ruby to talk to Flickr! What we need to do now is get this on to our website.

Step 6: Writing a flickr helper

It’s a good idea to separate out functionality like this into helpers and partials, rather than weave it directly into your existing code. So we’re going to create a flickr_helper.rb in the app/helpers directory like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# app/helpers/flickr_helper.rb

module FlickrHelper  
  def user_photos(user_id, photo_count = 12)
    flickr = Flickr.new(File.join(RAILS_ROOT, 'config', 'flickr.yml'))
    flickr.photos.search(:user_id => user_id).values_at(0..(photo_count - 1))
  end
  
  def render_flickr_sidebar_widget(user_id, photo_count = 12, columns = 2)
    begin
      photos = user_photos(user_id, photo_count).in_groups_of(2)
      render :partial => '/flickr/sidebar_widget', :locals => { :photos => photos }
    rescue Exception
      render :partial => '/flickr/unavailable'
    end
  end
end

The method which we will be calling from our view to display our flickr photos is:

1
render_flickr_sidebar_widget(user_id, photo_count = 12, columns = 2)

This method will prepare an array of photos and pass them to a partial (which we’ll get to in a minute). You may have noticed the call to in_groups_of which is quite interesting:

1
photos = user_photos(user_id, photo_count).in_groups_of(2)

Because we want two columns of photos in our little sidebar we need to group the array of photos. This is where in_groups_of comes into play. Let’s see how it works on the rails console:

1
2
3
4
5
6
7
8
>> Array(1..10).in_groups_of(4)
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, nil, nil]]

# Notice how it pads out the last array with nils

# We want to do group our flickr photos into groups of 2, one for each column
>> Array(1..6).in_groups_of(2)
=> [[1, 2], [3, 4], [5, 6]]

So our photos will group like so:

This grouped array gets passed to the flickr/sidebar_widget partial. Let’s take a look at that now:

1
2
3
4
5
6
7
8
9
10
11
12
13
# app/views/flickr/_sidebar_widget.html.erb

<div class="flickr">
  <ul>
    <% photos.each do |row| -%>
      <li>
        <% row.each do |p| %>
          <%= link_to(image_tag(p.url(:square), :class => 'flickr_photo', :title => p.title, :border => 0, :size => '75x75'), p.url_photopage) %>
        <% end %>
      </li>
    <% end -%>
  </ul>
</div>

I’m then styling this with the following CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.flickr ul
{
        list-style-type: none;
        margin: 0;
        padding: 0;
}
.flickr ul li 
{
        border-bottom: 0;
        margin: 0;
        padding: 0;
}

.flickr_photo
{
        width: 75px;
        height: 75px;
        padding: 12px 10px 32px 13px;
        margin: 0;
        background: #fff url(../images/pixellated/polaroid.jpg) no-repeat;
}

Each flickr thumbnail is placed on top of a little fake polaroid image I knocked up:

You may have also noticed a call in our flickr helper to an unavailable partial if there was an exception whilst trying to speak to flickr:

1
2
3
rescue Exception
  render :partial => '/flickr/unavailable'
end

I’m leaving that partial blank so if flickr is down it just doesn’t render anything. But if you want you can display something else instead of the flickr output then place it in the _unavailable.html.erb partial.

Step 7: Call the helper in your application.html.erb layout template

Just a simple call to…

1
<%= render_flickr_sidebar_widget('12864272@N02') %>

Of course you’ll put your own flickr ID in there instead of mine. Unless you really like my photos?! ;o)

Are we done yet?

Ah. Not quite! You may have noticed something about this when you started testing it…... it’s slow as hell! Every single page render now has to wait for a round trip to flickr. Not cool!

Step 8: Fragment caching to the rescue!

This is a perfect candidate for fragment caching. The flickr photos aren’t going to be changing too often so we can cache them and expire them when we know they have changed.

So we’re going to surround the call to the flickr helper in a fragment cache block:

1
2
3
<% cache ("flickr_sidebar") do %>
  <%= render_flickr_sidebar_widget('12864272@N02') %>
<% end %>

Remember this won’t speed up your renders on your development server as caching is disabled by default in development, but on production it will fly. It won’t cache the images (and why would you want to as flickr is built to serve images?) but it will cache the actual HTML code which required the costly API calls to flickr in order to generate.

Now we need some code to expire this cache when you’ve added some photos to flickr and you want to update the photos on the website. In fact, it would be really cool if you could expire this cache using capistrano, so you wouldn’t even need to ssh into your server to do this. For this I refer you to my previous post on expiring page and fragment caches using capistrano.

Ok, so this post is a bit earlier than advertised, but it’s better than being late! Following up from Rails on Oracle: Part 1 – Installing the oracle instant client on Mac OS X, now we are going to get rails to use our freshly installed oracle client…

Step 1: Download ruby-oci8

Download the latest tarball from the ruby-oci8 rubyforge page to your ~/Downloads directory. At the time of writing the latest is version 1.0.5.

Step 2: Make and install ruby-oci8

If you’ve followed the instructions from part 1 then you should have your oracle instant client installed in /opt/oracle/instantclient. If you’ve not installed the instant client yet then scoot off to part 1 and perform those steps before going any further. If you’ve installed it somewhere different then you will need to amend the following commands where appropriate:

1
2
3
4
5
6
7
cd ~/Downloads
tar xvzf ruby-oci8-1.0.5.tar.gz

cd ruby-oci8-1.0.5
ruby setup.rb config -- --with-instant-client=/opt/oracle/instantclient
make
sudo make install

Step 3: Install the oracle_enhanced adapter

1
sudo gem install activerecord-oracle_enhanced-adapter

Step 4: Configure you rails project to use an oracle database

Lets say with have the same oracle database as we had in part 1 which looked like so:

  • Host : myserver
  • domain : mydomain.com
  • Port : 1521
  • SID : mydatabase
  • Service : mydatabase.mydomain.com

We’d express this in our database.yml file with the following entry:

1
2
3
4
5
development:
  adapter: oracle_enhanced
  database: myserver:1521/mydatabase.mydomain.com
  username: myusername
  password: mypassword

Step 5: Profit!

Now (fingers crossed!) you should be ready. It’s been tricky for me to test this thoroughly because I don’t have access to a clean mac to start from scratch with. My mac is already set up and ready to go so it’s possible I could have missed something. If you have problems then leave a comment and I’ll try my best to sort you out and and update the instructions.

Looking for part 1?

Part 1 : Instructions on how to install the Oracle instant client on OS X and test it with sqlplus.

These instructions were performed using version 10.5.6 of OS X and the 10.1.03 Oracle instant client.

Step 1: Download the instant client from Oracle

We’re going to use the instant client because this is by far the easiest way to get up and running. Traditionally oracle clients have been quite heavy weight but the instant client is quick to download and easy to install.

Go to the appropriate download page for your CPU:

There are several download options. Download the following to your ~/Downloads directory:

  • Instant Client Package – Basic
  • Instant Client Package – SQL*Plus
  • Instant Client Package – SDK

Step 2: Install the files on your machine

I usually install these files in the /opt/oracle/instantclient directory. Assuming you’ve downloaded the zip files to your ~/Downloads directory we need to make a new home for our instant client and unzip the files there….

1
2
3
4
5
6
7
8
9
mkdir -p /opt/oracle/
cd /opt/oracle

mv ~/Downloads/instantclient*.zip .
unzip instantclient-basic-macosx-10.2.0.4.0.zip
unzip instantclient-sdk-macosx-10.2.0.4.0.zip
unzip instantclient-sqlplus-macosx-10.2.0.4.0.zip

mv instantclient_10_2 instantclient

Obviously if you have a slightly different version of the client you are going to need to amend those paths slightly.

Step 3: Create some symbolic links for the libraries

1
2
3
cd instantclient
ln -s libclntsh.dylib.10.1 libclntsh.dylib
ln -s libocci.dylib.10.1 libocci.dylib

Step 4: Set your ORACLE_HOME, NLS_LANG and DYLD_LIBRARY_PATH variables

You could do this in a couple of ways. Because I’m the only user of my machine I like to do this in my personal ~/.bash_profile. If you share the machine with someone who also wants to use the client you may want to put this in /etc/profile or/etc/bashrc. The choice is yours. I find ~/.bash_profile is cleaner:

1
2
3
export NLS_LANG="AMERICAN_AMERICA.UTF8"
export ORACLE_HOME=/opt/oracle/instantclient
export DYLD_LIBRARY_PATH=$ORACLE_HOME

Now you could close your terminal session and start a new one to force a reload or try this instead:

1
source ~/.bash_profile

Do a quick echo on $ORACLE_HOME and $DYLD_LIBRARY_PATH to make sure these environment variables are set correctly.

Step 5: Put sqlplus in your $PATH

There are couple of ways to do this. You could add /opt/oracle/bin to your $PATH or you could add a sym link to the sqlplus binary in a directory which is already in your $PATH. I’m going to do the latter as I don’t want to make my $PATH variable longer just for one executable.

I’ve already got /usr/local/bin in my $PATH so I’m going to make the sym link there:

1
ln -s /opt/oracle/instantclient/sqlplus /usr/local/bin/sqlplus

Just give that a test to make sure it’s getting found :

1
which sqlplus

This should return /usr/local/bin/sqlplus. Check your $PATH variable if it’s not working.

Step 6: Try it out!

Lets assume we’ve got the following Oracle database:

  • Host : myserver
  • domain : mydomain.com
  • Port : 1521
  • SID : mydatabase
  • Service : mydatabase.mydomain.com

And a username and password of :

  • Username : myuser
  • Password : mypassword

We can connect to this database using the following connect string:

1
sqlplus myuser/mypassword@//myserver:1521/mydatabase.mydomain.com

It’s a bit of a mouthful, but if that worked then we’re all up and running. In this instance we’re connecting over the default port of 1521. Because of this we can actually leave the port out and Oracle will assume the default:

1
sqlplus myuser/mypassword@//myserver/mydatabase.mydomain.com

Possible errors

ORA-12154: TNS:could not resolve the connect identifier specified

It couldn’t find your host. Try the following:

  • Instead of just putting myserver, try myserver.mydomain.com
  • Are you sure you got the port right? Oracle defaults to listening on 1521. Is the listener running on your server for sure? Try running lsnrctl status on the server just to double check it’s running and which port it’s on.

ORA-12514: TNS:listener does not currently know of service requested in connect descriptor

It’s found the host and the listener but it’s can’t find the database you’ve specified at that listener. The last part of the connect string where it says mydatabase.mydomain.com is where it’s falling over now. Again, the quickest way to check this is to ssh onto your oracle database server and query the listener with lsnrctl status which will also tell you which services the listener is listening on. Copy and paste the correct service into the sqlplus connect string and it should work.

ORA-01017: invalid username/password; logon denied

I think this one speaks for itself! If you’re sure of the username and password then maybe it contains characters which may need escaping? Try surrounding the username and password in double quotes:

1
sqlplus "myuser"/"mypassword"@//myserver:1521/mydatabase.mydomain.com

Coming in Part 2

Now that we can connect our machine to Oracle, in part 2 we’re going to get rails in on the fun as well. Check back in a week or so and I should have that post finished.

Update: Part 2 has now been published and shows you how to install the ruby-oci8 library, how to install the oracle_enhanced adapter and how to configure your database.yml.

Update 15/05/09: Added NLS_LANG to the environment variables
Update : Apparently this problem is specific to has_one relationships. If you’re updating a nested model through a has_many relationship then you may not have this problem.

I’ve just solved a little gotcha with the new nested models feature which shipped with rails 2.3. If you’ve been having the following error when you try to render your model/new forms then read on…

1
2
3
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.new_record?

What is causing the nil which knocks on to the NoMethodError on nil.new_record?

By following the instructions from rails guides I’d hit a brick wall and kept getting the error above whenever I’d try and render my new form. My code looked like so :

First the two models….

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# app/models/student.rb

# == Schema Information
# Schema version: 20090317153604
#
# Table name: students
#
#  id         :integer         not null, primary key
#  name       :string(255)
#  age        :integer
#  created_at :datetime
#  updated_at :datetime
#

class Student < ActiveRecord::Base
  has_one :address
  
  accepts_nested_attributes_for :address
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# app/models/address.rb

# == Schema Information
# Schema version: 20090317153604
#
# Table name: addresses
#
#  id           :integer         not null, primary key
#  house_number :integer
#  road         :string(255)
#  student_id   :integer
#  created_at   :datetime
#  updated_at   :datetime
#

class Address < ActiveRecord::Base
  belongs_to :student
end

And the view….

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# app/views/students/new.html.erb

<h1>New student</h1>

<% form_for(@student) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :age %><br />
    <%= f.text_field :age %>
  </p>

  <% f.fields_for :address do |a| %>
    <p>
      <%= a.label :house_number %>
      <%= a.text_field :house_number %>
    </p>
    <p>
      <%= a.label :road %>
      <%= a.text_field :road %>
    </p>
  <% end %>

  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

<%= link_to 'Back', students_path %>

The controller was left untouched.

As far as I can tell from the rails guide, unless I’m missing something really obvious, this is all that is needed. However I still get nil.new_record? errors when I try and hit that view.

The solution!

Thanks to the complex forms examples I was able to see where I was going wrong and put things right. It’s such a good idea to have working code examples of new features, thanks for that guys.

It turns out I needed to call build_address on my new student object. Makes sense I suppose. Otherwise we’re returning a nil from @student.address so we need to put a new object in @student.address so that its attributes can eventually be set.

And here’s how it works…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# app/views/students/new.html.erb

# Code from before and after the nested model has been removed for brevity

<% @student.build_address unless @student.address %>
<% f.fields_for :address do |a| %>
  <p>
    <%= a.label :house_number %>
    <%= a.text_field :house_number %>
  </p>
  <p>
    <%= a.label :road %>
    <%= a.text_field :road %>
  </p>
<% end %>

I assume that @student.build_address is the same as @student.address = Address.new. So it gives you a new blank address object, ready for the attributes to be pushed into. And now when rails calls new_record? on this object we don’t get a NoMethodError any more.

References

Sprinkle and passenger-stack v Deprec

Anton Jenkins | March 05, 2009

I decided to give passenger-stack a quick spin and I’ve got so say I’m impressed. I love the whole idea of being able to write recipes to build a server. It’s definitely the way forward as it’s so much easier having a DSL to spec a server.

However I don’t think I’ll be moving away from deprec just yet. The aim of sprinkle and passenger-stack is to be technology agnostic and it’s a great idea. Deprec is purely aimed at getting your rails app up and running as quickly as possible and it scratches this itch perfectly. And once you are running it’s the little touches which you start to appreciate. I’ve fallen in love with the way you can do something along the lines of :

1
2
3
4
5
6
7
8
cap deprec:passenger:config_gen

# Edit the newly created config files

cap deprec:passenger:config

# The config files are now pushed on to the server 
# and the relevant service is bounced!

This way of generating and pushing configuration changes to the components that deprec has installed is a fantastic time saver and I’m not sure how I could live without it now that I’ve been so spoilt.

In summary

So I guess what I’m getting at is passenger-stack and sprinkle is a really elegant solution, but if you are purely using this for rails then I’d personally be inclined to stick with deprec if it still works for you. However….. if there was a way of abstracting out the configuration goodness from deprec and mixing it with the actual building steps which passenger-stack and sprinkle performs then I think we’d have a perfect solution! Taking the best parts from both and mixing them together. Sounds great!

Adding a reCAPTCHA to enki

Anton Jenkins | March 04, 2009

There are several techniques to help prevent spam in your blog comments. I’ve opted for a captcha using the popular reCAPTCHA system. This post will show you how to apply reCAPTCHA to the enki blogging engine.

The idea with enki is that you clone the basic master tree and then merge in features you want from other people’s trees. So the following steps will show you how to take a basic enki blog from github and merge in the recaptcha branch to keep spam away.

Step 1 : Register at recaptcha.net and install the recaptcha gem.

When you sign up and register your domain at recaptcha.net they will give you two keys – a public key and private key. Keep these keys handy as you’ll need them later on.

Install the recaptcha gem with :

1
sudo gem install ruby-recaptcha

Step 2 : Clone enki and make a branch for your own blog

Assuming your blog is going to be called “myblogname” :

1
2
3
git clone git://github.com/xaviershay/enki.git myblogname
cd myblogname
git checkout -b myblogname

Step 4 : Merge in the reCAPTCHA branch

1
2
git remote add recaptcha git://github.com/antonjenkins/enki.git
git pull recaptcha recaptcha

Now we should have a branch call myblogname with a clean install of enki merged with the recaptcha branch.

Step 5 : Configure the blog to use your reCAPTCHA keys

If you look in the environment.rb file you should see a little section right at the top for you to paste your public and private keys :

1
2
3
4
5
# config/environment.rb

# reCAPTCHA keys. Obtain these for your domain from http://recaptcha.net/
RCC_PUB = "Put your reCAPTCHA public key in here"
RCC_PRIV = "Put your reCAPTCHA private key in here"

Step 6 : Configure enki as usual

That concludes the specific steps needed for the reCAPTCHA support. All that remains is to follow Xavier Shay’s instructions for configuring enki as detailed on the enki github page :

1
2
3
4
5
6
  cp config/database.example.yml config/database.yml
  # Edit config/enki.yml and config/database.yml to taste
  rake db:migrate
  rake spec
  ./script/server
  # Load http://localhost:3000/admin in your browser

Now when you upload your blog to the web your comments form should be protected with reCAPTCHA. You probably wont see the reCAPTCHA on your development box because usually the public and private reCAPTCHA keys only work on the domain you’ve specified when you requested them (unless you checked the global box).

Resources

The key to this technique is making your cache sweepers easy to call from a rake task. For this website I’ve created a simple site sweeper which flushes the entire page cache :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# app/sweepers/site_sweeper.rb

class SiteSweeper < ActionController::Caching::Sweeper
  observe Page, Post, Comment, Tag, Tagging
  
  def after_save(site)
    self.class::sweep
  end
  
  def after_destroy(site)
    self.class::sweep
  end
  
  def self.sweep
    cache_dir = ActionController::Base.page_cache_directory
    unless cache_dir == RAILS_ROOT+"/public"
      FileUtils.rm_r(Dir.glob(cache_dir+"/*")) rescue Errno::ENOENT
      RAILS_DEFAULT_LOGGER.info("Cache directory '#{cache_dir}' fully swept.")
    end
  end
end

By declaring the sweep method as a class method we make it easy to call from rake to force a sweep.

To do so we need to create a new rake file :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# lib/tasks/pixellated.rake

namespace :pixellated do
  namespace :cache do
    desc "Expire the flickr_sidebar fragment cache"
    task :expire_flickr => :environment do
      ActionController::Base.new.expire_fragment('flickr_sidebar')
      RAILS_DEFAULT_LOGGER.info("Flickr sidebar cache swept")
    end

    desc "Expire page cache"
    task :expire_pages => :environment do
      SiteSweeper.sweep
    end

    desc "Expire everything"
    task :expire_all => [:expire_flickr, :expire_pages] do
      RAILS_DEFAULT_LOGGER.info("All caches swept")
    end
  end
end

The tasks in here allow me to flush the page cache as well as flush the flickr_sidebar fragment which you can see to the right of each page. It takes around 8 seconds to talk to flickr and refresh this page element so it’s a perfect candidate for fragment caching.

We can now use rake to flush the caches from the command line :

1
2
3
rake pixellated:cache:expire_flickr
rake pixellated:cache:expire_pages 
rake pixellated:cache:expire_all

But what about on the production server?

Well that’s your local machine sorted, but we need a way to flush the caches on the live server. Capistrano to the rescue again!

Because we can perform cache flushes using rake we just need a way to invoke the rake tasks on the server. Of course we will need to do a deploy to get our newly created rake tasks on to the server first (very important and easy to forget!) :

1
cap deploy

Now we can add the following capistrano tasks to depoy.rb to invoke these rake tasks remotely :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# config/deploy.rb

namespace :pixellated do
  namespace :cache do
    set :remote_rake_cmd, "/usr/local/bin/rake"

    desc "Expire everything"
    task :expire_all do
      run("export RAILS_ENV=production; cd #{deploy_to}/current; #{remote_rake_cmd} pixellated:cache:expire_all")
    end

    desc "Expire page cache"
    task :expire_pages do
      run("export RAILS_ENV=production; cd #{deploy_to}/current; #{remote_rake_cmd} pixellated:cache:expire_pages")
    end

    desc "Expire the flickr_sidebar fragment cache"
    task :expire_flickr do
      run("export RAILS_ENV=production; cd #{deploy_to}/current; #{remote_rake_cmd} pixellated:cache:expire_flickr")
    end
  end
end

Simple. Now if I’ve posted some pictures up to flickr and I want my caches flushed I just run…

1
cap pixellated:cache:expire_all

... and it’s sorted. Plus it uses an existing sweeper used elsewhere in the application, so it’s DRY.

Further reading

Ana Nelson has an entire post on calling rake remotely using capistrano if you are interested in exploring this.

Uploading files for enki using capistrano

Anton Jenkins | February 23, 2009

Because the Enki blogging engine currently doesn’t have a method for uploading files for use in your posts I needed to come up with a quick and easy solution. This solution will also work for any website which doesn’t have an upload facility built in. The technique used is easily replicated.

Could we use git?

It would be tempting to just check the images that are going to be used in posts into git and be done with it. They could be stored in the /public/images directory and get uploaded onto the server when you deploy. But this is messy. Version control is for files that are part of the infrastructure of your site, not the actual content.

So we need a different solution which maintains this separation.

Capistrano

When you deploy with capistrano it creates a symbolic link from current/public/system to the shared/system directory. Because we don’t want to lose our uploaded images whenever we redeploy it makes perfect sense to store our images in the shared area (as this persists across deploys) and have the current deploy link across to them.

But first we need to get them there. What we’re going to do is create the file structure on our local development copy of the site and then use capistrano and rsync to push it up to the server.

To start with we need to create the system directory in public. Oh, and don’t forget to add this folder to your .gitignore! As discussed above, we don’t want this in version control. I’ve opted for the following structure to mimic the structure of the URLs that Enki uses :

As you can see, all the images and files will be in the system/assets directory. You’ll need to ssh into your server and create the assets directory in the corresponding system directory before taking the next step.

We should be at this stage :

Now we need a capistrano task in our deploy.rb to push the files in our local assets directory up to the assets directory on the server :

1
2
3
4
desc "Sync assets on server with development public/system/assets"
task :sync_assets do
  `rsync -qrpt --delete --rsh=ssh public/system/assets deploy_user@myserver.com:/path-to-my-app/shared/system/assets`
end

Note : Don’t forget to alter the above command and change the destination to fit your environment. Unless of course your app does live at deploy_user@myserver.com:/path-to-my-app/!

The combination of rsync and ssh is perfect for uploading the files up to the server. It is important to be aware of the --delete option used. If we delete a file at the source then when we next rsync it will delete the corresponding file at the destination. So make sure you keep all your images on your local machine otherwise the next sync will ditch them on the server!

With everything in place it’s simply a case of firing off the task :

1
cap sync_assets

You won’t get much clue as to whether it worked so ssh into the server and make sure everything has copied over. If it’s not worked then try copying the rsync command and running it from the command line to look at the output. You might have got the paths wrong or something simple like that.

If it’s worked the files can be accessed from your posts using the textile markup like so :

1
!/system/assets/2009/02/23/uploading-files-for-enki-using-capistrano/assets-file-structure.png!

As a quick solution it works quite well!

Join the war on IE6

Anton Jenkins | February 20, 2009

It’s about time!

For too long web designers have had to wrestle IE6 into doing their bidding. The many hours we spend on IE6 bugs are hours we could be investing in better features for our users. Thankfully some developers in Norway have decided to make a stand and spread the word to users that they need to upgrade their IE6 browsers.

By adding something like the following code to your application’s layout file you can add a message only visible to IE6 users asking them to consider upgrading their browsers :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--[if lte IE 6]>
<div style="border:3px solid #ff0000; margin:8px 0; background:#ff8080; color:#000; width:580px;">
  <h4 style="margin:8px; padding:0; font-weight:bold; color:#000">
      Warning : You are using an old version of Internet Explorer
  </h4>
  <p style="margin:8px; padding:0;">Many websites are dropping support for older versions of Internet
    Explorer because they do not conform correctly to industry standards. Not following standards makes
    building websites much harder and wastes time that could be invested in making the website better for
    everyone else.</p>

  <p style="margin:8px; padding:0;">By upgrading your browser you will not only be enhancing your own
    experience but also relieving a significant burden from web designer's shoulders, freeing them to build
    better websites for everyone.</p>

  <p style="margin:8px; padding:0;">There are many modern browsers to choose from...
    <ul>
      <li><a style="color: #000; text-decoration:underline; outline:none" href="http://getfirefox.com">FireFox</a></li>
      <li><a style="color: #000; text-decoration:underline; outline:none" href="http://google.com/chrome">Chrome</a></li>
      <li><a style="color: #000; text-decoration:underline; outline:none" href="http://opera.com">Opera</a></li>
      <li><a style="color: #000; text-decoration:underline; outline:none" href="http://apple.com/safari">Safari</a></li>
    </ul>
  </p>
</div>
<![endif]-->

When viewed with IE6 the user will see the following :

Warning : You are using an old version of Internet Explorer

Many websites are dropping support for older versions of Internet Explorer because they do not conform correctly to industry standards. Not following standards makes building websites much harder and wastes time that could be invested in making the website better for everyone else.

By upgrading your browser you will not only be enhancing your own experience but also relieving a significant burden from web designer’s shoulders, freeing them to build better websites for everyone.

There are many modern browsers to choose from…

Obviously you’ll probably want to play around with the styling to make it fit your site, but the general gist is there for you to hack around with. How you do it is not important, getting involved and helping to spread the word is the main issue.

Hopefully this will gain some momentum around the world and we can move on from the pains of writing IE6 friendly sites.

Using basic authentication to hide your website

Anton Jenkins | February 18, 2009

Suppose you’re developing a rails website for a client and you’d like them to be able to access it on a staging server, but you want to keep it hidden from prying eyes until it’s ready to launch. The quickest and cleanest way is to utilise HTTP basic authentication.

By adding the following code to your application.rb you will protect all pages on the site with a username and password dialog :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#app/controllers/application.rb

require 'digest/sha1'

class ApplicationController < ActionController::Base

before_filter :authenticate

protected
  def authenticate
    if Rails.env == "production"
      authenticate_or_request_with_http_basic do |username, password|
        username_hash = Digest::SHA1.hexdigest(username)
        password_hash = Digest::SHA1.hexdigest(password)
        username_hash == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33" && password_hash == "62cdb7020ff920e5aa642c3d4066950dd1f01f4d"
      end
    end
  end
end

What’s with the “0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33”?

Rather than put the username and password in plain text here I’ve obscured them using SHA1 to make it a little more secure. Suppose we want a username of ‘foo’ and and password of ‘bar’ we can use the rails console to obtain the hashes required and paste them in to the above code snippet.

1
2
3
4
5
6
7
8
#./script/console

>> require 'digest/sha1'
=> []
>> Digest::SHA1.hexdigest("foo")
=> "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
>> Digest::SHA1.hexdigest("bar")
=> "62cdb7020ff920e5aa642c3d4066950dd1f01f4d"

Won’t my tests fail?

This is why we specify the rails environment using :

1
if Rails.env == "production"

By doing this we ensure that our tests wont be asked to authenticate and also our development environment will be left alone. If Rails.env doesn’t work for you then try changing this to RAILS_ENV.

Disabling the authentication

Turning it all off is as simple as removing the before filter from your application.rb :

1
before_filter :authenticate  # comment out or remove this line

You may as well leave the authenticate method sitting in your apllication.rb just in case you need to lock things down quickly at a future date.

Other uses for this technique

This method is also very useful for securing the admin areas of your site as detailed in this railscast. If you require something a bit more comprehensive you might want to check out Lockdown, AuthLogic or Restful Authentication.