Trying to follow the law of demeter, I'm in the process of refactoring code. The goal is for every model to have methods that serve as APIs for other models to extract data.
Organization has an instance method #suppliers_for_purchaser, which returns all suppliers for one purchaser. This method has been successfully tested in organization_spec.rb.
Price has a class method .latest_prices_for_purchaser. This class method takes one argument (an instance of Organization) and uses this argument to call Organization#suppliers_for_purchaser. This causes an error schema does not exist in RSpec:
Failures:
1) Price.latest_prices_for_purchaser returns latest prices for purchaser
Failure/Error: Price.latest_prices_for_purchaser(purchaser).should have(2).prices
ActiveRecord::StatementInvalid:
PG::Error: ERROR: schema "organization" does not exist
: SELECT COUNT(*) FROM "organizations" INNER JOIN "partnerships" ON "organizations"."id" = "partnerships"."partner_id" WHERE "partnerships"."organization_id" = 1 AND (organization.organization_role.name = 'supplier')
# ./spec/models/price_spec.rb:24:in `block (3 levels) in <top (required)>'
Models (simplified)
class Organization < ActiveRecord::Base
# self referencing n:n table
has_many :partners, :through => :partnerships
# some more associations, all tested
# successfully tested in an RSpec unit test for this model
def suppliers_for_purchaser
partners.where('organization.organization_role.name = ?', "supplier")
end
end
class Price < ActiveRecord::Base
def self.latest_prices_for_purchaser(purchaser)
suppliers = purchaser.suppliers_for_purchaser
# some more code that doesn't get executed because it crashes on the line above
end
end
price_spec.rb (simlified)
describe Price do
describe ".latest_prices_for_purchaser" do
# passes
it "responds" do
Price.should respond_to(:latest_prices_for_purchaser)
end
it "returns latest prices for purchaser" do
purchaser = create(:organization_purchaser)
supplier = create(:organization_supplier)
partnership = create(:partnership, organization: purchaser, partner: supplier)
2.times do
price = create(:price, created_at: 10.hours.ago, supplier: supplier, purchaser: purchaser)
end
Price.latest_prices_for_purchaser(purchaser).should have(2).prices
end
end
end
Update
cheeseweasel found the solution. Unit testing Price.latest_prices_for_purchaser only worked when changing Organization#suppliers_for_purchaser to:
partners.joins(:organization_role).where('organization_roles.name = ?', "supplier")
The issue is with the suppliers_for_purchaser method - when constructing queries, you need to explicitely define any joins to related tables, so the following:
partners.where('organization.organization_role.name = ?', "supplier")
needs to have the organization_role join defined:
partners.joins(:organization_role).where('organization_roles.name = ?', "supplier")