Dynamic finders in has_many associations

I have these 3 models.

class Ivr < ActiveRecord::Base
has_many :klusterings, :dependent => :destroy
has_many :klusters, :through => :klusterings, :uniq => true
end

class Kluster < ActiveRecord::Base
has_many :klusterings, :dependent => :destroy
has_many :ivrs, :through => :klusterings, :uniq => true
end

class Klustering < ActiveRecord::Base
belongs_to :kluster
belongs_to :ivr
end

I faced 2 problems and didn’t manage to find any good tutorial.

  1. Given some Kluster A, I want to find all the Ivrs that aren’t in A.
  2. I want to find all the Ivrs that aren’t in ANY Kluster.

– I managed to do 1. with:
@kluster = Kluster.find(params[:id])
@all_ivrs = Ivr.find(:all)

@ivrs = (@all_ivrs - @kluster.ivrs)

– And I did 2. with:
@all_ivrs = Ivr.find(:all).select{ |ivr| ivr.klusters.empty? }

But 1. does two SQL queries, one possibly very big (Ivr.find(:all)).
And 2. does that too.

Any way to do this, preferibly with dynamic finders?

On 24 Apr 2008, at 13:06, Paulo P. wrote:

I have these 3 models.

  1. Given some Kluster A, I want to find all the Ivrs that aren’t in A.
  2. I want to find all the Ivrs that aren’t in ANY Kluster.

You need some lower level stuff:

Ivr.find :all, :joins => ‘left outer join klusterings on
klusterings.ivr_id = ivrs.id’, :conditions => ‘kluster_id IS NULL’
finds ivrs associated with no klusters
Ivr.find :all, :joins => “left outer join klusterings on
klusterings.ivr_id = ivrs.id AND kluster_id =
#{@kluster.id}”, :conditions => ‘kluster_id IS NULL’
should find the ivrs not associated with @kluster
(typed quickly in mail, so might be slightly off, but should get you
there in the end)

Fred

I’ve done some similar lookups along these lines…

  1. Given some Kluster A, I want to find all the Ivrs that aren’t in A.
    @kluster = Kluster.find(…A…)
    @ivrs = Ivr.find(:all, :conditions=>[“id not in (?)”,
    @kluster.ivr_ids.join(‘,’)])
  1. I want to find all the Ivrs that aren’t in ANY Kluster.
    ivr_ids = Kluster.find(:all).collect{|kluster| kluster.ivr_ds}.uniq
    @unklustered = Ivr.find(:all, :conditions=>[“id not in (?)”,
    ivr_ids.join(‘,’)])

On Apr 24, 8:15 am, Frederick C. [email protected]