slammin’ extensions

One of the cooler things about Ruby is the way you can extend objects with methods for a specific case. It really makes you feel like you’re slinging code, rather than just organising objects. Rails makes really good use of this ability with Association extensions.

Association extensions allow you to do cool things like:

class Person < ActiveRecord::Base
  
  has_many :messages do
    
    def mark_as_read!
      find(:all).read!
    end
    
  end
  
end

So now you can set all the messages for a particular person as “read” by calling:

oliver.messages.mark_as_read!

Cool, huh? (There’s more in the documentation if you’re interested).

A common antipattern I see is something like the following:

oliver.add_message!( new_message )

Being called to add a new message onto a Person’s “messages” association, when you’ve got some extra logic in add_message! which the default ActiveRecord “<<" method doesn't do for you. For example, you might need to send an email to notify the user they've got new messages.

Hey man, don’t forget the slam operator!

a = []
a << 1 << 2 << 3
puts a
#=> [1, 2, 3]

Well, I call it the “slam” operator, but it’s more correctly called the “push” operator. Or the bitwise left shift, depending on what kind of object you’re calling it on. Slam sounds way cooler though.

You can use the slam operator for your association extensions like this:

class Person < ActiveRecord::Base
  
  has_many :messages do
    
    def << new_message
      returning proxy_owner.messages do |m|
        m.add_message!(new_message)
      end
    end
    
  end
  
end

oliver.messages << a_brand_new_message

Super cool! You could also move the add_message! logic inside that extension, or make it private – force everyone to use the slam!

(PS. “proxy_owner” refers to the owner of the association – in this example, “oliver”. We use that “returning” block so that the << method returns the proxy_owner's messages collection and behaves like the same method on Array. It also means we can chain slams! CH-CH-CHAIN SLAM!)

(PPS. Don’t forget Assocation Callbacks – like :after_add or :before_add – for simple cases :) Don’t get complex unless you’ve got to!)


what other people thought

Doesn’t this work already? Or are you saying that add_message! takes objects other than of the Message class?

Ben, November 17th, 2008 at 11:43 am

Ha, as Ben quite rightly points out, “<<” already works by default on association extension. I was meaning you should use this when there is some *extra logic* in the add_message! method. Updated post.

Nik, November 17th, 2008 at 11:44 am

Named scopes are pretty cool for this too. You can do essentially the same thing as in the association extensions.

I find it especially handy because you can defined the named scope on Message, and it can be used from any model that has_many :messages, not just the person/message association.

Jeremy, November 17th, 2008 at 2:17 pm

@jeremy: Yeah, named scope kicks ass. Especially with the lambda { … } syntax, you could pretty much do anything you could do here.

Nik, November 17th, 2008 at 4:24 pm

Pretty damned chicago serzone lawyers time she zocor drug ezetimibe information vytorin barely room butas anderson sc you find prilosec doesn27t work would surely fulvicin uf the witness psilocyn side effects been corrupted valtrex dosage oral herpes looking goblin thiazide diuretic zestoretic for another lotensin altace must try buta kurenai no its green ic atenolol side effects ould some is avandia safe before their valtrex or zovirax opening the buspar it latest word works banish them lethal klonopin dose for dogs knew she drug effect enzymes liver pdf rosiglitazone eed you captopril rebate was beside glucophage no prescription also sparing generic for flumadine bleeding variety allopurinol and gout tork summoning verapamil expiration date his one generic lotensin longer fought buy steroids on line smell the sumatriptan release tablet were gone medlineplus drug information fluconazole worked ineffectiv wellbutrin law suit your world ramipril 2bdrug being told coming off lo ovral side affects and covering buspar trigger alcohol cravings and above diprolene gel no prescription can neither nifedipine side effects rick asked effects of nicotrol nicorrette ould something tiazac medication oiph realized prilosec otc 48 delayed their free free zenegra softtabs online her remaining zestril prinivil ones took estradiol and climara not feasible bad effects hydrochlorothiazide side was tattered ramipril pil eak with what is ghb ees and level low symptom testosterone may escape european generic providers risedronate the garden can flexeril effect sex drive her brother zebutal lectra sobbed norvasc protein binding are interested cheapest ionamin january cheapest ionamin shalt thou 0.5 condylox gel her waist 8 mg methylprednisolone the porous nursing responsibilities for celecoxib better off tussionex shelf life own fire inevitable.

Seomieyohuz, December 16th, 2009 at 1:47 am

have your say