views:

32

answers:

3

Hi guys.. I have a the following situation: pages has many groups.

Now i am trying to find the first page who hasn't got a group with activerecord. I tried things like this:

Page.find(:first, :joins => :groups, :select => 'DISTINCT `pages`.*')

but of course no luck so far.

+2  A: 

One solution could be to add a counter_cache for the groups.

In Group.rb

belongs_to :page, :counter_cache => true

Then, you need to create a migration

def self.up
  add_column :pages, :groups_count, :integer, :default => 0

  Page.reset_column_information
  Page.find(:all).each do |p|
    Page.update_counters p.id, :groups_count => p.groups.length
  end
end

def self.down
  remove_column :pages, :groups_count
end

So, now you could do:

Page.first(:conditions => { :groups_count => 0 })
jordinl
Ok yes this would work. BUT i don't really like it that i should create another migration for just this simple statement. :( Then i just could do it with sql.. But thanxs!
+2  A: 

This is more an SQL problem than ActiveRecord. What you need is to join the 2 tables but select those who are not referenced in the join table.

Page.first(:include => :groups, :conditions => ["`#{Group.table_name}`.id IS NULL"]
# The opposite query would be
Page.first(:include => :groups, :conditions => ["`#{Group.table_name}`.id IS NOT NULL"]
# Note that this slightly different than just: 
Page.first(:include => :groups)
# This produces a IN query, rather than join.

Also :joins does not work because it creates a INNER JOIN, as opposed to OUTER JOIN which is required in this case.

Swanand
YEs this is even better! (i solved the problem with looping through all the pages.. not really efficient ;) ) .. thanxs!:D
A: 

Something like:

Page.find(:all, 
          :select => "pages.*, count(groups.page_id) group_count", 
          :joins => :groups, 
          :group => "pages.id having group_count = 0)
mark