Namespaces, models, and rails associations

I spent several hours banging my head against this. I figured I’d share the solution that a co-worker eventually showed me.

I was working with 3 models all inside the same module.

1
2
3
4
5
6
7
8
9
10
class Billing::Customer < ActiveRecord::Base
  has_and_belongs_to_many :Orders
end

class Billing::Orders < ActiveRecord::Base
  belongs_to :Department
end

class Billing::Department < ActiveRecord::Base
end

In the controller for model for Customers I wanted to allow users to filter the entire list of customers by various criteria. One of the filters was for first name, which is an attribute of the customer model. I could do the search like this:

1
Billing::Customer.find(:all, :conditions => "first_name LIKE ")

A second filter was only customers who had ordered something. This was also easy using the :include parameter to the find method.

1
2
3
Billing::Customer.find(:all,
                       :conditions => "Orders.id IS NOT NULL", 
                       :include => [:Orders])

But the third filter was trickier. I wanted to list the customers that had orders associated with any department.

Without the namespace this is the proper way to do a find with nested includes.

1
2
3
Billing::Customer.find(:all,
                       :conditions => "Departments.id",
                       :include => [:Orders, {:Orders => :Department}])

Because the Orders model is in the Billing module that returned an error that “Orders” was an uninitialized constant. It worked at the rails console if I first ran include Orders but I couldn’t make it work in my controller.

The proper way to do this with namespaced models is to make the association more explicit by specifying the class names.

1
2
3
class Billing::Customer < ActiveRecord::Base
  has_and_belongs_to_many :Orders, :class_name => "Billing::Orders"
end

With that change the find worked properly and I was able to do the search.