Tuesday, December 30, 2008

Rails and Merb combine!

No on saw this one coming. On December 23rd it was announced that Rails 3 will be the product of merging Rails and Merb frameworks.

Check out these links for more information

http://rubyonrails.org/merb
http://yehudakatz.com/2008/12/23/rails-and-merb-merge/

Tuesday, December 2, 2008

IE File Download - Security Warning

File Download - Security Warning
Do you want to save this file, or find a program online to open it....

Have you ever seen this error when making an ajax request in IE? In particular this seems to happen when using the remote_form_for or remote_form_tag helper and try submitting the form via javascript. The expected result would be that the form would be submitted via ajax and then a RJS file would execute some Javascript on the client's page. Instead we get a stupid IE download popup.

This one always comes back to bite me when I add a new features to a site and I've been blissfully programming away in FF neglecting the red headed stepchild IE. Then comes the head scratching followed by some screaming when Google fails to return any sort of valuable search results on this subject. I am going to post the issue and resolution for myself and hopefully it will help some other people out there.

Here is an example of the HTML generated from remote_form_for.

<form method="post" id="user_form" action="/users"
onsubmit="new Ajax.Request('/users', {
asynchronous:true,
evalScripts:true,
parameters:Form.serialize(this)});
return false;"></form>

And here is some javascript function that would submit that form.

$('user_form').submit();

First off when you submit this form in IE it seems that it sends out an ajax request because the full page does not reload. As it turns out when you call $('user_form').submit() in IE it never calls the onsubmit handler so it never has a chance to return false and prevent a full page submission. Since the form is not submitted via ajax IE thinks you want to download the response, ie the RJS file, hence the popup. What makes this even more tricky is that the RJS you wanted to execute actually gets executed so it looks like it was an actual ajax submission but it in fact was not.

The simple solution is when you are trying to submit a remote form via javascript you should explicitly call the onsubmit handler like this.

$('user_form').onsubmit();

Doing it this way ensures that you are submitting the form via ajax and behavior will be consistent across all browsers.

"Im a PC and I handle form submissions differently"

Monday, November 17, 2008

ActionMailer with Gmail. Must issue a STARTTLS command first

If you ever tried sending e-mail via ActionMailer with gmail settings you may have received the following error:

530 5.7.0 Must issue a STARTTLS command first. k41sm7289021rvb.4

The problem is that Gmail requires TLS authentication but the standard Ruby net/smtp library doesn't support TLS.

Of course there is a helpful plugin created by Marc Chung to overcome this barrier. You can find it here and manually add it to your project or you can export it to your plugin directory.

$ cd vendor/plugins
$ svn export http://code.openrain.com/rails/action_mailer_tls/

Either way make sure you require 'smtp_tls'

Now all you need is to update your smtp_settings if you haven't done so already.


ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "domain.com",
:user_name => "user@domain.com",
:password => "password",
:authentication => :plain
}

You can now enjoy the benefits of a free email server.

Sunday, November 16, 2008

What happened to Save the Developers from IE6 movement?

WTF?

Awhile back we found a nice site called Save The Developers that was dedicated to rid the world of IE6. The site was hosting some javascript that you could use to throw down a nice "Save the developers and upgrade your IE" message to the IE6 users of your site.

Well as of sometime recently that url redirects you to a Microsoft support site? WTF? Did Mr. Softy just crush these guys? If you have info on this I would love to know.

Conspiracy Theory? :)

Update

Stop IE6 campaign logo

Stop IE 6. Another campaign against IE6.

Free the Web! Good luck guys.

IE6 hangs when downloading compressed images from AWS S3

Like many new sites we store uploaded user images to S3. We are always trying to improve the experience of users so recently we started compressing these images using gzip.

Well, it turns out that for some reason IE6 completely freezes for about 10 minutes when trying to download one of these files. Of course no problems in any other browser.

Luckily IE6 is only 12% of our user base, so now we are forced to have zipped and unzipped images.
Argh IE6! Save the developers!

I hope this helps someone as it drove us nuts trying to figure it out.

Thursday, November 6, 2008

Hotmail in Ubuntu fix

Not too long ago there was an update to Hotmail basically rendering it unusable in Ubuntu. This is just one more item to add to the list of reasons why Microsoft sucks. Personally I prefer Gmail but I have a legacy account on Hotmail that I must check every now and then.

After searching around for awhile I came across several solutions to get Hotmail working. One required opening up the about:config settings and changing the general.useragent.vendor from Ubuntu to Firefox. This works but it is required every time you restart your browser. There was also another solution that involved creating some .js script and placing it in your profile folder?!? Finally I found a somewhat decent solution. This should work in any Linux type system.

First you need to install the User Agent Switcher add on.

Then you need to create a new User Agent profile by going to
Tools -> User Agent Switcher -> Options -> Options

Then click on User Agents tab and hit the Add button.

Add the following fields:

Description : [whatever]
User Agent : Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3
App Name : Mozilla Firefox
App Version : 5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3
Vendor : [blank]
Vendor Sub : [blank]


Here is what it should look like (some of the characters got cut off at the end)














Then click on OK OK

Now when you want to use Hotmail you can just quickly switch the User Agent Profile to the newly created one. When you are done, simply switch back to the Default Profile.

Friday, October 31, 2008

Capistrano Subversion password

Recently I ran into a problem with Capistrano asking for my password when performing a svn+ssh checkout even though I had my SSH keys configured correctly.

Capistrano hits the svn twice when performing a checkout. The first time it queries the most recent revision number and the second time to perform the actual checkout. It was during this second request that I was being asked for my password. After searching for awhile and trying multiple suggestions I finally came across a solution.

In app/config/deploy.rb :


ssh_options[:keys] = ["#{ENV['HOME']}/.ssh/id_rsa"] #Obviously needed
#default_run_options[:pty] = true #Didn't work for me
#ssh_options[:paranoid] = false #Didn't work for me
ssh_options[:forward_agent] = true #Ah hah.. Success!

Basically the ssh_options[:forward_agent] = true option forwards the first authenticated ssh session (the one that queries the revision number) to the second one (the one that performs the checkout).

If you are seeing the same problem this may just be the fix for you are looking for!

Wednesday, October 29, 2008

Quick Tip - Console Goodies

I just want to mention two quick little goodies for the rails console.

Tip #1 - Reloading

Have you ever been running the console and after modifying your source you notice that the console has not picked up your changes? This usually occurs when you adding/removing/editing associations on a model, messing around with your vendor or lib directory, changed an environment config or anything else that only gets loaded once.

Luckily there is a way to quickly reload your whole console environment without having to quit and restart saving you precious seconds. Actually when I used to develop in a windows environment starting up the console would take a very long time so this would save more than just a few seconds.


$ ruby script/console
Loading development environment (Rails 2.1.1)
>> User.first.posts
NoMethodError: undefined method `posts' for #<Class:0xb6f55a08>
# Now add the posts association on User
>> reload!
Reloading...
=> true
>> User.first.posts
=> [#<Post id: 1 ....>]

As you can see you just need to run the unsubtle command reload! to reload the environment.

Tip #2 - Sandbox

Have you ever want to muck around in your development database or dare I say production database and wished your temporary changes would not persist? Perhaps you wanted to test that new :dependent => :destroy association or perhaps you wanted to be evil (if only for a second) and destroy all the existing users just to make you feel powerful. Here's how to do it.


$ ruby script/console production --sandbox
Loading production environment in sandbox (Rails 2.1.1)
Any modifications you make will be rolled back on exit
>> User.count
=> 214
>> User.destroy_all #Insert evil laugh here
=> [#<User id: .... ]
>> User.count
=> 0
>> exit

$ ruby script/console production --sandbox
Loading production environment in sandbox (Rails 2.1.1)
Any modifications you make will be rolled back on exit
>> User.count
=> 214

All you need to do here is add the --sandbox flag when starting up the console. Its basically like having a huge transaction block around your whole console session and by exiting you are throwing and exception and everything gets rolled back.

Tuesday, October 28, 2008

Delgation Pattern in Ruby

The Delegation Pattern is a common pattern in all OO programming languages and is generally preferred over the use of inheritance. The beautiful thing about Ruby/RoR is that there are many ways to go about implementing this pattern.

Say we have the following classes:


class User
attr_accessor :first_name, :last_name

def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
end

class Whatever
def initialize(user)
@user = user
end
end

And for whatever reason we want to be able to access the object user's first and last name attributes from the object whatever like the following:


>> user = User.new("Rob", "Zotter")
=> #User:0xb7bf3b98...
>> whatever = Whatever.new(user)
=> #Whatever:0xb7bf1a14...
>> whatever.first_name
=> Robert
>> whatever.last_name
=> Zotter

Here are some ways to go about doing this.

Solution #1 : Wrapper Methods

We could simply add wrapper methods to the Whatever class that simply delegate the calls to the @user object.


class Whatever
def initialize(user)
@user = user
end

def first_name
@user.first_name
end

def last_name
@user.last_name
end
end

As you can see this quickly gets tiring as more and more methods are added to the User class that we would want to delegate. It also bloats the Whatever class.

Solution #2 : Method Missing


class Whatever
def initialize(user)
@user = user
end

def method_missing(method, *args, &block)
if @user.respond_to?(method)
@user.send(method, *args, &block)
else
raise NoMethodError
end
end
end

He were eliminate the need to continuously update Whatever class with wrapper methods when the User class changes by utilizing Kernel#method_missing. Now when the object whatever is sent a message that it does not know it will check the @user object to see if it responds to it and if it does it will delegate that method to it otherwise throwing a NoMethodError. Although this is an improvement over solution #1 it still has its drawbacks. First it is slower since it needs to search the whole Whatever class hierarchy before it reaches method_missing. Second, we do not have control over which methods can be delegated, they simply all get delegated to @user if @user responds to it. Third, whenever using method_missing it is always a little harder for anyone reading your source code to determine exactly what you are trying to do.

Solution #3 : SimpleDelegator


require 'delegate'

class Whatever < SimpleDelegator
def initialize(user)
super(user)
end
end

Here we are using SimpleDelegator which is an implementation of the Delegator interface. We just have to pass in the user to super during instantiation and all methods on user will be available on whatever. This is a little more transparent then using method_missing but by subclassing SimpleDelegator we are preventing ourselves from being able to subclass any other class in the future. We also do not have control over which methods get delegated. Lastly, this way uses inheritance to accomplish composition?!?

Solution #4 : Forwardable


require 'forwardable'

class Whatever
extend Forwardable
def_delegators :@user, :first_name, :last_name

def initialize(user)
@user = user
end
end

Here we are using the Forwardable module. We just have to simply extend our class with the Forwardable module and we explicitly set which methods to delegate using the def_delegators method. As you can see the first argument to that method is the object to which to delegate to and then the following arguments are which methods to delegate to that object.

Finally one last example using ActiveSupport#delegate which you get by default if you are running RoR.

Solution #5 : ActiveSupport Delegate


class Whatever
delegate :first_name, :last_name, :to => :@user

def initialize(user)
@user = user
end
end

This is very similar to the previous example but I prefer this over the former because I think it just reads a little nicer. In this example you list the methods to delegate first then you define what object to delegate to using the :to option. ActiveSupport extends Module with the delegate method so there is no need to extend the Whatever class before using it.

Solutions #4, #5 use metaprogramming techniques to dynamically add class methods to the Whatever class using class_eval which essentially make the class look like it does in solution #1.

As you can see there are many ways to implement the Delegation pattern in Ruby and I'm sure there are plenty more ways that aren't mentioned here. Like the old saying goes theres is more than one way to skin a cat and Ruby certainly gives you more than enough sharp pointy objects to do it with.

Thursday, October 23, 2008

Big Day for Amazon EC2

Today Amazon Web Services made some big announcements. We've been using AWS for over a year now and have been very happy with it.

* Amazon EC2 is now in full production. The beta label is gone.
* There's now an SLA (Service Level Agreement) for EC2.


Finally! This will make our customers and investors sleep better at night! It's nice to see something not in a perpetual beta.

* Microsoft Windows is now available in beta form on EC2.
* Microsoft SQL Server is now available in beta form on EC2.


Yawn... Microsoft in the cloud doesn't excite me much.

* We plan to release an interactive AWS management console.

I think the command line tools are just fine, but OK.

* We plan to release new load balancing, automatic scaling, and cloud monitoring services.


Oh Yeah! To me, this has been the last piece of the puzzle.

Load balancing in the cloud has been a "roll you own solution". The current solution is to use a software load balancer like HAProxy. However, this requires more machines, more management, and more hops and therefore more money. Round Robin DNS is a poor man's solution, do not even go there.

My wish list.

  • Better reliability than S3, please!

  • L4 load balancing

  • L7 content switching/filtering - Sticky Sessions

  • HTTP rewrite and compression

  • SSL acceleration

  • Cheap - cheaper than having small instances running a software load balancer

  • An easy web service API to configure all this

Kudos to the AWS team!

Monday, October 20, 2008

Ruby Syntax Highlighting in Blogger using Google syntaxhighlighter

In a previous post I used the syntax gem to get ruby syntax highlighting for this blog.

Well I just found a better way! Enter the syntaxhighlighter on Google Code.

It 100% Javascript based so there is no need to mess around with html yourself. Only drawback is that you need a place to host the files.

Getting it to work in Blogger


Go to Layout -> Edit Html and place the following right before the closing </head>.

<link href='http://.../stylesheets/syntax/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>
<script language='javascript' src='http://.../javascripts/syntax/shCore.js'/>
<script language='javascript' src='http://.../javascripts/syntax/shBrushRuby.js'/>
<script language='javascript' src='http://.../javascripts/syntax/shBrushXml.js'/>
<script language='javascript' src='http://.../javascripts/syntax/shBrushJava.js'/>
and then at the bottom after the closing </body> tag add:

<script language='javascript'>
//dp.SyntaxHighlighter.ClipboardSwf = 'http://.../flash/syntax/clipboard.swf';
dp.SyntaxHighlighter.BloggerMode();
dp.SyntaxHighlighter.HighlightAll('code');
//]]>
</script>

Then in your posting you just surround the code in a pre tag with the class name set to the language you are displaying:

<pre name='code' class='ruby'>
  ...
</pre>

The html above was put in a <pre name='code' class='xml'> tag. ;) Remember to escape your opening brackets with &lt;.

Now isn't that nice.

Sunday, October 19, 2008

Multiple rake tasks. Running rake tasks from a task

Rake is a very useful ruby build tool very similar to that of Ant for Java.

Sometimes you may want to run several rake tasks in succession and today I will go over several ways you can go about doing this.

Say we want to completely drop our existing database, recreate it and populate it with some sample data via a custom rake task called 'populate' (not shown here).

A naive way of accomplishing this would be to do the following:

 $ rake db:drop
(in /home/rob/project/)
$ rake db:create
(in /home/rob/project/)
$ rake db:migrate
(in /home/rob/project/)
$ rake db:populate


Besides just being horribly repetitive, this method requires you to wait to the completion of each migration before typing the next thus preventing you from grabbing the o so needed cup of coffee while your db is migrating. This method also reloads the rails environment before each migration which is completely useless and time consuming.

"Ok" you say, "I got the answer" and type the following:

$ rake db:drop && rake db:create && rake db:migrate && rake db:populate


This is one step better as you do not have to wait to the completion of each task before typing in the next, but we still have the problem of typing all of those commands as well as reloading the environment each time.

Sounds like its time for a custom rake task.
Lets create a rake file called db.rake and place it in our [project-root]/lib/task/ directory.

namespace :db do
task :everything => [:environment, :drop, :create, :migrate, :populate]
desc "Recreate everything from scratch including pre-populated data"
end
end


You can then just run one command

$ rake db:everything


For those of you familiar with Java you will noticed that the rake syntax of 'task :everything => [:environment, :drop, :create, :migrate, :populate]' is exactly like Ant's depends attribute.

For those of you not familiar with Ant ill quickly explain. Basically what 'task :everything => [:environment, :drop, :create, :migrate, :populate]' means is that the the task 'everything' depends on these other tasks so run those first.

Ok, so now we greatly improved our initial version in that we do not have to type all of the individual commands or wait for the completion of each task before continuing. We also get the benefit of not having to reload the environment before each task (other than the first time of course).

A problem arises though when we want to do anything else with this migration. For example, say we want to execute some logic or print out a simple message before and after each task execution. To accomplish this we would have to move all of the tasks out of the prerequisites section and move them into the actual task block. But how can we run another rake task from within a rake task? The Rake::Task api will help us find the answer we are looking for.

 task :everything => :environment do
desc "Recreate everything from scratch, including test data"
%w(drop create migrate populate).each do |task|
puts "Performing task #{task}"
#Some logic could go here
Rake::Task["db:#{task}"].invoke
end
end


The key to take out of this last example is the Rake::Task#invoke method. The method accepts a task (or tasks) and well... invokes it (or them).

So with the help of rake and Rake::Task#invoke we have a nice clean way of running multiple rake tasks.

Tuesday, October 14, 2008

Autotest notifications in Ubuntu, Mac and Windows

Autotest part of the ZenTest package is a great testing tool that will automatically run your RSpec tests when you make a change to any of the source files.

If you don't know about RSpec then you must have been living in a cave and I suggest you check that out first.

Today I am going to teach you how to setup automatic notifications in Ubuntu that will allow you to display the results of your tests in nice little window like so.



First make sure you have the libnotify binaries installed.

$ sudo apt-get install libnotify-bin

Then you'll need to install the actual autotest notification gem

$ sudo gem install carlosbrando-autotest-notification --source=http://gems.github.com

Easy enough. Ok now for the hard part of configuring it.... oh wait, did I say hard? I meant ridiculously easy.

$ sudo an-install

The above command will first backup then overwrite your ~/.autotest config file so you may just want to manually append the following if you have any existing configurations.

# ~.autotest
require 'autotest_notification'
SPEAKING = false
DOOM_EDITION = false
BUUF = false
PENDING = false
STICKY = false

As you can see there are a few extra options you can play with till your little heart is content. You can even get notified by voice if you install espeak and pass a '-s' switch to an-install.

An alternative to automatic notifications in Ubuntu is mumbles which you may want to check.

What about Mac and Windows?

The best thing about automatic notifications is that is fully compatible with Mac OS and Windows.

For Mac you'll need to install Growl and in Windows you'll need Snarl. Installation is just as easy but slightly different in these enviroments so consult the README.txt for detailed instructions.

Enjoy

Sunday, June 15, 2008

IRB/Console tweaks

Today ill explain how you can tweak your irb and rails console. First you'll need an irb configuration file called '.irbrc' which should be placed in your home directory. You'll need to create one if it doesn't already exist. Now you can add the following.

#Load the readline module.
IRB.conf[:USE_READLINE] = true

#Remove the annoying irb(main):001:0 and replace with >>
IRB.conf[:PROMPT_MODE] = :SIMPLE

#Always nice to have auto indentation
IRB.conf[:AUTO_INDENT] = true

#History configuration
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"

#Load modules if not already loaded
IRB.conf[:LOAD_MODULES] = [] unless IRB.conf.key?(:LOAD_MODULES)
unless IRB.conf[:LOAD_MODULES].include?('irb/completion')
IRB.conf[:LOAD_MODULES] << 'irb/completion' #Autocompletion of keywords
IRB.conf[:LOAD_MODULES] << 'irb/ext/save-history' #Persist history across sessions
end

The comments should be pretty much self-explanatory. By fat the most useful feature has to be the auto-completion of keywords. So now you can just hit tab tab to display all methods of on an object.

The next biggest feature has to be the persistence of the history across sessions. Anything that helps me save a few repetitious keystrokes is a big gain in my book.

Since console is just basically irb on steroids you will have all this functionality there too!

You can also add rails/console configurations here. Just make sure you are in the right environment before trying anything rails specific so irb doesnt blow up.

if ENV['RAILS_ENV']
#do something rails specific
end


A good way to separate out your rails specific configurations is to include it in another file and just load it from .irbrc This idea and the following are slight modifications of the snack recipes from the great book Advanced Rails Recipes (Authors of the recipe are at errtheblog.com). You'll need to create a file called .railsrc in your home directory.

if ENV['RAILS_ENV']
load "#{ENV['HOME']}/.railsrc"
end


One helpful method I like to have in .railsrc is the ability to turn on and off ActiveRecord logging to the console to help analyze/debug my sql.

#Enable ActiveRecord logging
def loud_logger(enable = true)
logger = (enable == true ? Logger.new(STDOUT) : nil)
ActiveRecord::Base.logger = logger
ActiveRecord::Base.clear_active_connections!
end


Now you can easily turn on and off your ActiveRecord logging.

>> SomeModel.first
=> # < SomeModel id: 1.. >
>> loud_logger
>> SomeModel.first
SomeModel Load (0.000442) SELECT * FROM some_models LIMIT 1
>> loud_logger false
>> SomeModel.first
=> # < SomeModel id: 1.. >

Tuesday, June 3, 2008

MySQL NULL sort order

Say we have an application that keeps track of tasks that need to be completed.

A task will have a name, description and an optional expiration date.

A possible schema could look something like the following.

create_table :tasks do |t|
t.column :name, :string, :null => false
t.column :description, :text
t.column :expiration, :datetime
end


Now lets try to display all Tasks ordering by their expiration. We will just display the expiration for the sake of brevity.

>> puts Tasks.all(:order => 'expiration ASC').map(&:expiration)
nil
nil
nil
Fri June 4th 00:00:00
Sat June 5th 00:00:00


The problem here is that by default null values appear at the top of the list. How can we display this list in ASC order but null values at the bottom of the list? After scouring around for awhile I finally came across a solution. It turns out that MySQL has a way to control the sorting of NULL values by adding a '-' before the field.

>> puts Tasks.all(:order => '-expiration DESC').map(&:expiration)
Fri June 4th 00:00:00
Sat June 5th 00:00:00
nil
nil
nil


Now we can list all Tasks ordered by their expiration date with NULL values at the bottom.

Friday, May 2, 2008

Cheating is fun with the cheat gem!

errtheblog.com released a great gem called cheat.

Installation is a snap

$ sudo gem install cheat

Now you have access to a wide array of cheat sheets. Cheat sheets are basically like wiki pages that can be accessed from the command line, editable and all. Don't believe me? Give it a try

$ cheat rspec | less

rspec:
INSTALL
=======
INSTALL rspec
=============
$ sudo gem install rspec
OR
$ ./script/plugin install git://github.com/dchelimsky/rspec.git

INSTALL rspec_on_rails plugin
=============================
$ ./script/plugin install git://github.com/dchelimsky/rspec-rails.git


BOOTSTRAP THE APP
=================
$ ./script/generate rspec
create spec
create spec/spec_helper.rb
create spec/spec.opts
create previous_failures.txt
create script/spec_server
create script/spec

....

Cheat is not even rails specific. There are a whole slue of helpful commands that you can refer to as you go about your everyday programming. Just use the cheat sheets command to list them all.

$ cheat sheets
All Cheat Sheets:
acts_as_authenticated
acts_as_state_machine
acts_as_taggable_on
address
administrateme
agile
alias
ambition
ansi
arts
as3_formulas
ascii
assert
assertions
assert_block

....and it keeps going and going

Include vs Extend

A common cause of confusion in Ruby is discerning the difference between Module#include and Object#extend and when to use one over the other.

A few examples will help us understand. Lets create a file example.rb

cd module Coolness
def cool_method
puts "This is one cool method!"
end
end

class A
include Coolness
end

a = A.new
a.cool_method


Then we run it

$ ruby example.rb
This is one cool method!


When you include a module from another module (remember all classes are modules) you are in essence adding in all of the included module's constants, methods, and module variables to the module that is including it. It's a mouthful, I know. So all of the methods of the module are available as instance methods. Now lets see what happens when we modify our file and use extend instead.

class A
extend Coolness
end

a = A.new
a.cool_method


$ ruby example.rb
example.rb:14: undefined method `cool_method' for # (NoMethodError)


When you use extend you are adding the modules methods to the instance from which it is called on. In our case we are extending the module from the singelton class A so all the modules methods are available on the singelton class A, not on the instances of class A. I know, its another mouthful. So when you use extend in this way you are in essence adding the modules methods as class methods, not instance methods. So to execute cool_method we must call it as a method the class A itself.

class A
extend Coolness
end

A.cool_method


$ ruby example.rb
This is one cool method!


If we wanted cool_method to be available to an instance of class A we need to explicitly extend the instance.

class A
extend Coolness
end

a = A.new
a.extend(Coolness)
a.cool_method


$ ruby example.rb
This is one cool method!


So to summarize if you wanted to add instance methods to a class you should use include. If you want to add class methods to a class you should use extend. And finally, if you want to add instance methods to one particular instance of a class you should use extend on the instance itself.

Let me know if you have any questions.

Friday, April 18, 2008

ActsAsFerret and computed ferret fields

The ActsAsFerret plugin automatically indexes your model when saving.

The acts_as_ferret method takes a whole slew parameters which includes the fields to be indexed. For example say we have a User model:

 acts_as_ferret :fields => {    
:last_name => {:boost => 10,:store => :yes},
:first_name => {:boost => 1, :store => :yes},
:title => {:boost => 1, :store => :yes},
:introduction => {:boost => 10,:store => :yes}
}, :ferret => {:or_default => true}, :remote => true


This will add last_name, first_name, title and introduction to the index. These fields are just database columns. The symbol for field is really just a method call and so this how we can add computed or nested ferret fields for indexing.

Suppose the user has a set tags with a simple 'has_many :tags' declaration.

Then we can create a simple method in the user model like this.
def user_tags
tags.map(&:name).join(',')
end


and add this method(field) to the acts_as_ferret method

  acts_as_ferret :fields => {    
:last_name => {:boost => 10,:store => :yes},
:first_name => {:boost => 1, :store => :yes},
:title => {:boost => 1, :store => :yes},
:introduction => {:boost => 10,:store => :yes},
:user_tags => {:boost => 10,:store => :yes}
}, :ferret => {:or_default => true}, :remote => true


Now we have the user's tags in the User index.

Friday, April 11, 2008

Quick Tip - extract_options!

ActiveSupport added a helpful method named 'extract_options!' that

"Extracts options from a set of arguments. Removes and returns the last element in the array if it‘s a hash, otherwise returns a blank hash."

So when we have a method that can accept multiple attributes the last of which could be a hash of options, instead of doing...

def some_method(*attributes)
configuration = {
:some_default => 'value'
}
configuration.update(attributes.pop) if attributes.last.is_a?(Hash)
.......
end

We have the more elegant...


def some_method(*attributes)
configuration = {
:some_default => 'value'
}
configuration.update(attributes.extract_options!)
.......
end

Wednesday, April 9, 2008

Missing host to link to! Please provide :host parameter or set default_url_options[:host]

When using a link_to or url_for in an ActionMailer and you need to set the host.

In production.rb or the appropriate env config file.

config.action_mailer.default_url_options = { :host => 'www.example.com' }

Saturday, March 15, 2008

When private is not private

In Java if we have a class with a private class method like so...

public class MyJavaClass {
private static void privateMethod() {
System.out.println("I am private method");
}
}

Trying to call the 'privateMethod' class method is futile.

public class Testing {
public static void main(String args[]){
MyJavaClass.privateMethod(); //This will not work!
}
}

Matter of fact you can not even compile the above class!

Testing.java:3: privateMethod() has private access in MyJavaClas
MyJavaClass.privateMethod();

If we have a similar Ruby class and call the private method there is no problem.

class MyRubyClass
private
def self.private_method
puts "I am a private method"
end
end

>> MyRubyClass.private_method
I am a private method
=> nil

What gives?!

As it turns out you can not simply create a class method in a private section and have it actually be private. Reading through the Ruby API I came across the solution to achieve the desired behavior. There is a method in Module called 'private_class_method' with the following signature.

mod.private_class_method(symbol, ...) => mod

Now if we slightly modify our MyRubyClass we get the results we would expect.

class MyRubyClass
private
def self.private_method
puts "I am a private method"
end
private_class_method :private_method
end

>> MyRubyClass.private_method
NoMethodError: private method 'private_method' called for MyRubyClass:Class
from (irb):26


*Note: Private instance methods behave as expected without any modifications.

Monday, March 10, 2008

Quick Tip - to_proc

We all know that & (ampersand) is used to denote a block variable but what you may not know is that Rails ActiveSupport (and soon to be in ruby 1.9) has a nice extension on Symbol that can make use of this convention by adding a to_proc method.

For example instead of:

["This", "blog", "is", "great"].map {|w| w.upcase}
=> ["THIS", "BLOG", "IS", "GREAT"]


We could simplify it by:

["This", "blog", "is", "great"].map(&:upcase)
=> ["THIS", "BLOG", "IS", "GREAT"]


What ruby ends up do is calling the to_proc method on that symbol and it coerces into a block!

Here is a link to the documentation and for those who are lazy I have posted the source below.

# File lib/extensions/symbol.rb, line 23
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end

Saturday, February 9, 2008

Custom Rails Validations - Keeping it DRY(2)

Last week I added a custom validation for zip/postal codes. Now we make that available to all ActiveRecord models.

The best way is to create a plugin for all your custom validations. We have a plugin for all our ActiveRecord extensions. Its easier to test and its reusable across projects.

So we have our Validations module location in 'vendor/plugins/active_record_ext/lib'

module ValidationSystem
def self.included(base) # :nodoc:
base.extend ClassMethods
end

module ClassMethods
def validates_as_zip_code(*attr_names)
configuration = {
:message => 'is an invalid zip code',
:with => /(^\d{5}$)|(^\d{5}-\d{4}$)|(^[ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d)/,
:allow_nil => false}
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
validates_format_of attr_names, configuration
end
end

end


Now we just need to tell ActiveRecord to include this in Base so its available for all model classes.

'vendor/plugins/active_record_ext/init.rb'

ActiveRecord::Base.class_eval do
include ValidationSystem
end

Wednesday, February 6, 2008

Require vs Load

In ruby there are two main ways to include additional source files into working enviroment. One way is with the Kernel#load method and the other is with the Kernel#require method.

So what are the main difference and when should one be used over the other?

Some simple examples should clear up any confusion.

Say we have a very useful file called 'useful.rb' that has the following contents.

puts "This file is so useful I just want to use it everywhere!"


Now lets play in our nifty IRB and 'require' our destined to be hugely popular file.

>> require 'useful'
This file is so useful I just want to use it everywhere!
=> true


Ahh all is well in the world. Now lets try to load it.

>> load 'useful'
LoadError: no such file to load -- useful
from (irb):2:in 'load'
from (irb):2
>>


As you can see 'load' was unable to locate the file. Lets try adding the .rb to extension and see what happens.

>> load 'useful.rb'
This file is so useful I just want to use it everywhere!
=> true


There we go. So the first difference I want to point out is that 'load' requires that you explicitly add the file extension while 'require' does not. 'require' will automatically search your path for files with the given name and automatically append .rb, .so, .o and .dll extensions to try to locate the proper file.

Now lets see what happens if we 'require' and 'include' our file a second time.

>> require 'useful'
=> false
>> load 'useful.rb'
This file is so useful I just want to use it everywhere!
=> true


As you an see requiring the file a second time fails but including it passes. This is because when you 'require' a file it will not reload itself if it has already been loaded. This is in contrast to 'load' will always reload the file.

Why would you ever use 'load' then? Well the truth is most of the time you will be using 'require' but there are circumstances where 'load' is preferably. Rails for example uses 'load' while in development mode as to guarantee any changes to the source will invalidate any existing cache that the web server may have thus always displaying your most recent changes.

I hope this post clears up any confusion.

Sunday, February 3, 2008

Custom Rails Validations - Keeping it DRY

One of the validations that keeps coming up for us is zip/postal code. Sure you can use 'validates_format_of' with a regexp but it's nice to keep that regexp logic all in one place. We recently had to support Canadian Postal Codes so it was nice to update it just in one spot.

   def validates_as_zip_code(*attr_names)
configuration = {
:message => 'is an invalid zip code',
:with => /(^\d{5}$)|(^\d{5}-\d{4}$)|(^[ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d)/,
:allow_nil => false}
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
validates_format_of attr_names, configuration
end

Thursday, January 10, 2008

Ruby code formatting in Blogger on Ubuntu

Last week we got blog formatting for the Mac working. What about Ubuntu???

There is a slight modification to get this to work.

First you need you install 'xsel'

sudo apt-get install xsel


Now just modify last weeks code of 'pbpase' and 'pbcopy' to 'xsel --clipboard'.

Sunday, January 6, 2008

Ruby code formatting in Blogger on Mac

How do you format ruby code for blogger?

Update


I am now formatting using syntaxhighlighter



I followed this nice posting and tweaked it for the mac. Looks like Wolfman is running KDE.

My codetohtml.rb now looks like this:

require 'rio'
require 'rubygems'
require 'syntax/convertors/html'

if ARGV.size > 0
code = File.read(ARGV[0])
else
code = `pbpaste`
end

convertor = Syntax::Convertors::HTML.for_syntax "ruby"
@code_html = convertor.convert( code )

puts @code_html

if ARGV.size > 0
fn = "#{File.basename(ARGV[0], File.extname(ARGV[0]))}.html"
rio(fn) << @code_html
else
#put the results back on the clipboard, NB this may fail if there are shell specific characters
system("echo \"#{@code_html}\" | pbcopy ")
end


Then you post the CSS in the html under 'Layout' -> 'Edit Html'

pre {
background-color: #f1f1f3;
color: #112;
padding: 10px;
font-size: 1.1em;
overflow: auto;
margin: 4px 0px;
width: 95%;
}

/* Syntax highlighting */
pre .normal {}
pre .comment { color: #005; font-style: italic; }
pre .keyword { color: #A00; font-weight: bold; }
pre .method { color: #077; }
pre .class { color: #074; }
pre .module { color: #050; }
pre .punct { color: #447; font-weight: bold; }
pre .symbol { color: #099; }
pre .string { color: #944; background: #FFE; }
pre .char { color: #F07; }
pre .ident { color: #004; }
pre .constant { color: #07F; }
pre .regex { color: #B66; background: #FEF; }
pre .number { color: #F99; }
pre .attribute { color: #5bb; }
pre .global { color: #7FB; }
pre .expr { color: #227; }
pre .escape { color: #277; }