about me

I'm a 35'ish year old web application developer from South Portland, Maine. I love meeting fellow techies, drop me a line if you want to talk shop.

Categories

ActiveRecords and methods on your model associations

Posted on 03/08/2009 at 05:16 AM

I left PHP to program in Ruby a little over a year ago now, though technically I think I focused more on learning Rails during my first month. Like most who made the journey, I found Ruby a joy to work with, and Rails to have everything I needed to make great web apps. But to this day, the part of Rails I struggle the most with is ActiveRecord. There’s just so much magic in there ...

I want to share a syntax I learned this evening for declaring methods on an association in ActiveRecord.

In my system, Users can post content either as themselves, or as approved Affiliate identity. But since other Users might also want to post as this Affiliate, I use a has_many :through relationship to manage this. Imagine an Affiliate is a local business or organization, and Users might belong to multiple instances of them. This may explain things better.

class Affiliate ActiveRecord::Base
  has_many 
:affiliations
  has_many 
:users, :through => :affiliations
  attr_accessor 
:status
end

class Affiliation ActiveRecord::Base
  belongs_to 
:affiliate
  belongs_to 
:user
  attr_accessor 
:status
end

class User ActiveRecord::Base
  has_many 
:affiliations
  has_many 
:affiliates, :through => :affiliations
end

I needed to create a select menu for Users creating content in my system so they could select an optional alternate Affiliate identity to post as. The thing is ... these relationships aren’t cut and dry. Both the Affiliate and the Affiliation need to have a status of ‘approved’ or that User cant post as that Affiliate identity.

That said, I needed to populate this select menu for the User. At first I started thinking like this:

class User ActiveRecord::Base
  has_many 
:affiliations
  has_many 
:affiliates, :through => :affiliations

  def approved_affiliates
    affiliates
.with_status(:approved).find(
      :
all
      :include => 
[:affiliations],
      :
conditions => ["affiliations.status = 'approved'"]                 
    
)
  
end 
end

@affiliates current_user.approved_affiliates.collect {|p[ p.namep.id.to_s ] }

But looking in my User model, this didn’t seem very elegant and I wanted to find a way to keep the method definition attached to the code where I declare the association. I was already using a named_scope in my Affiliates model “with_status(:approved)” (not shown here) and so I thought I might be able to combine it with a similar named scope on the join.

So, really what I needed was an association method to scope the Affiliate AND the Affiliation to have statuses of ‘approved’. Try as I might I couldn’t figure out the syntax for this. If you know how it can be done, please do share.

What I ended up with, and am quite happy with is ...

class User ActiveRecord::Base
  has_many 
:affiliations
  has_many 
:affiliates, :through => :affiliations do
    
def with_combined_statuses(status)
      
find(:all, :include => [:affiliations], :conditions => ["affiliations.status = ? AND affiliates.status = ?"statusstatus])
    
end
  end
end

@affiliates current_user.affiliates.with_combined_statuses('approved').collect {|p[ p.namep.id.to_s ] }

So, I learned you can pass a block to the association and declare methods there, as well, those methods can accept parameters.

Yay me smile

Leave a comment?

Please use Pastie or Gist if you need to write code in your comments.

Name:

Email:

Location:

URL:

Remember my personal information

Notify me of follow-up comments?

Please enter the word you see in the image below:


RailsConf 2008 Often times I will release code for free or go that extra distance to help others online. If my skills were useful to you, please consider a small donation. Thank you very much.

recommend me!

Search

You Can Find Me

@ github.com
@ twitter.com
@ calendaraboutnothing

My Wishlists

@ Amazon.com

My Other Sites

Foundation's Edge, RJones Family, We're Not.com (only for staging), Ailee Jones (same as rjones for now)

Friends of Mine

Aaron, Barnaby, Brian, Chris, Dirk, Frank, Four, Justin, Matt, Mike, Monty, Paul, Sean, Travis

IRC Hangouts

I can usually be found lounging on irc.freenode.net while I work, on the following channels: #fauna, #github, #hello-heroku, #jquery, #passenger, #ruby, #rubyonrails, #slicehost, #sproutcore, #textmate, #werenot.