views:

682

answers:

2

I am building a rails site and am having trouble with the associations. Basically I have the following:

class Publication < ActiveRecord::Base
  belongs_to :category
  has_one    :site, :through => :category
  named_scope :on_site,        lambda {|s| {:include => [:site], :conditions => ['sites.slug != ?', 's']}}
end
class Category
  belongs_to :site
  has_many   :publications
end
class Site
  has_many :categories
  has_many :publications, :through => :categories, :foreign_key => 'category_id'
end

Publication.first.site produces the first publication's site, site.first.publications does as well.

The trouble is with the on_site named scope, which produces the following error with something like Publication.on_site('s')

Mysql::Error: Unknown column 'categories.category_id' in 'on clause': SELECT 
`publications`.`id` AS t0_r0, `publications`.`shoot_id` AS t0_r1, 
`publications`.`category_id` AS t0_r2, `publications`.`title` AS t0_r3, 
`publications`.`slug` AS t0_r4, `publications`.`publish_on` AS t0_r5, 
`publications`.`created_at` AS t0_r6, `publications`.`updated_at` AS t0_r7, 
`publications`.`description` AS t0_r8, `publications`.`media_base_path` AS t0_r9, 
`sites`.`id` AS t1_r0, `sites`.`name` AS t1_r1, `sites`.`created_at` AS t1_r2, 
`sites`.`updated_at` AS t1_r3, `sites`.`slug` AS t1_r4, `sites`.`description` AS t1_r5, 
`sites`.`dhd_merch_id` AS t1_r6, `sites`.`members_area_url` AS t1_r7 FROM `publications`
 LEFT OUTER JOIN `categories` ON (`publications`.`id` = `categories`.`category_id`)  
 LEFT OUTER JOIN `sites` ON (`sites`.`id` = `categories`.`site_id`) WHERE (sites.slug != 's')

I need that join to be publications.category_id = categories.id, any idea on what I've got wrong?

+1  A: 

Well, I found a solution using the :joins option for the scope, if anyone's interested. I'd still like to know if it's possible without using :joins however.

  named_scope :on_site,        lambda {|s| {:joins =>
   ['LEFT OUTER JOIN `categories` ON  (`publications`.`category_id` = `categories`.`id`) ',
   'LEFT OUTER JOIN `sites`      ON  (`sites`.`id` = `categories`.`site_id`)'],
   :conditions => ['sites.slug = ?', s]}}
Andrew Cholakian
I hope you can comment on Jesse's reply, because it seems valid.
Walt Gordon Jones
+2  A: 

Well, here is a problem with your current implementation:

LEFT OUTER JOIN `categories` ON (`publications`.`id` = `categories`.`category_id`)

That SQL snippet is created by this association definition in Site:

has_many :publications, :through => :categories, :foreign_key => 'category_id'

The foreign_key there is not correct. Rails is looking for a column in categories called category_id, and expects the value of that column to match some publication id. But there is no correct foreign_key option that you can set, because the categories table looks like it does not have references to the publications table - it is the other way around.

I'm not sure it is possible to make ActiveRecord's has_many :through association work through an intermediate has_many association. But I think that you can use the nested association feature to make this work:

class Publication < ActiveRecord::Base
  belongs_to :category
  #has_one    :site, :through => :category
  named_scope :on_site,        lambda {|s| {:include => { :category => :site }, :conditions =>  ['sites.slug != ?', s]}}
end

Another issue is that you put s in quotes in the conditions array. It should not be in quotes.

Jesse Hallett
Jesse, I'll give that a shot on monday, I'm pretty sure I tried all that stuff before I resorted to doing a join and it didn't work however (I'm pretty sure what you posted was my first implementation, before I just started doing all kinds of other stuff).As for the s in quotes I don't think that really was the crux of it. If you look at the generated SQL I pasted the join is trying to match publication.id with category.category_id. When in fact it needs to be publication.category_id with category.id.
Andrew Cholakian
Oh yes, the quoted `s` is a completely separate issue. I just wanted to point that out.
Jesse Hallett
Well, it looks like the code you posted doesn't fix it, I still need to do the joins manually. Your named_scope produces the same error, it tries to look for a column `sites_publications_join.category_id` which doesn't exist
Andrew Cholakian
Did you try removing the `has_many :publications...` line from Site? That might be confusing things.
Jesse Hallett