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.
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:
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.
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.
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.
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.