views:

550

answers:

3

Trying to get along with Sphinx/Thinking Sphinx for the first time.

I've got my models defined as follows (simplified):

class Branch < ActiveRecord::Base
  has_many  :salesmen, :class_name => "User"
  has_many :leads, :through => :salesmen
end

class User < ActiveRecord::Base
  belongs_to :branch
  has_many :leads, :foreign_key => "owner_id"
end

class Lead < ActiveRecord::Base
  belongs_to :owner, :class_name => "User"

  define_index do
    indexes company_name    
    indexes :name, :sortable => true
    has owner.branch_id, :as => :branch_id
    indexes [owner.last_name, owner.first_name], :as => :owner_full_name, :sortable => true 
  end

end

Anytime I call

Branch.first.leads.search

I get

RuntimeError: Missing Attribute for Foreign Key branch_id

What am I doing wrong?

A: 

I believe you're missing a :through option on your branch relation. Try updating to:

class Lead < ActiveRecord::Base
  has_one :branch, :through => :owner
Ben
I'm afraid that :through is not a valid option for belongs_to association. AFAIK.
Milan Novota
Sorry, I meant changing to a has_one relationship. Updated my answer now!
Ben
Unfortunately, this won't work since owner belongs_to a branch and has_one :branch, :through => :owner won't give me anything but an exception.
Milan Novota
+1  A: 

The issue is that Thinking Sphinx needs branch_id as an attribute in your index, so it can restrict results to just the relevant branch (because you're searching within an association).

It's not clear from your associations (or maybe that just my dire need for sleep) whether a lead belongs to a branch via the owner, or directly as well. If the former, Ben's suggestion is probably correct. Otherwise, try adding the following to your define_index block:

has branch_id, :as => :direct_branch_id

An alternative approach, after reading the comments, is to add your own search method to the leads association in Branch. A vague attempt (you will need to debug, I'm sure):

has_many :leads, :through => :salesmen do
  def search(*args)
    options = args.extract_options!
    options[:with] ||= {}
    options[:with][:branch_id] = proxy_owner.id
    args << options
    Lead.search(*args)
  end
end

This should get around the fact that you do not have a direct reference to the branch from Lead. The only possible issue is that I'm not sure whether custom extensions get loaded before or after what Thinking Sphinx injects. Give it a shot, see if it helps.

pat
Thanks pat. Yes, a lead belongs to a branch via the owner and there's no direct association in there. The problem with Ben's suggestion is that there's no such a thing as belongs_to :through. :(
Milan Novota
Erm, I'm a bit confused as to how the belongs_to call on Lead works then?
pat
Oh! I'm sorry, the association between Leads and Branches from Leads is not defined in my model (I confusingly added belongs_to :branch into the Lead model; I was a bit sleepy, too - it's removed now). Now, the problem is, that there's no way (at least as I can see) of how to define an association which is on one side defined as has_many :through (because there's no such a thing as belongs_to :through). I've tried many things, such as delegation, but nothing worked. I believe I'm making some ridiculous mistake, though. Anyways, thanks, for your efforts.
Milan Novota
In case an edit doesn't fire off a notification -- have just added a different approach that may help.
pat
That actually seems to work, Pat. Thank you so much! Learned something new, today.
Milan Novota
A: 

If you say a Lead belongs_to a Branch, then you must have a branch_id in the leads table. Since you don't, it's not a belongs_to relationship. I think you need something like this:

class Branch < ActiveRecord::Base
  has_many :leads, :through => :salesmen
  has_many :salesmen, :class_name => "User" 
end

class User < ActiveRecord::Base
  belongs_to :branch # users table has branch_id
  has_many :leads, :foreign_key => "owner_id"
end

class Lead < ActiveRecord::Base
  belongs_to :owner, :class_name => "User" # leads table has owner_id

  define_index do
    indexes :company_name    
    indexes :name, :sortable => true
    has owner.branch_id, :as => :branch_id
    indexes [owner.last_name, owner.first_name], :as => :owner_full_name, :sortable => true 
  end

end
Sarah Mei
Thanks Sarah, I didn't provide complete model - of course I have the belongs_to :branch association in my User model, already. Unfortunately, that doesn't help.
Milan Novota