デメテルの法則に従おうとして、コードのリファクタリングを行っています。目標は、他のモデルがデータを抽出するための API として機能するメソッドをすべてのモデルに持たせることです。
組織には、1 人の購入者のすべてのサプライヤーを返すインスタンス メソッド #suppliers_for_purchaser があります。このメソッドは、organization_spec.rb で正常にテストされています。
Price にはクラス メソッド .latest_prices_for_purchaser があります。このクラス メソッドは 1 つの引数 (Organization のインスタンス) を取り、この引数を使用して Organization#suppliers_for_purchaser を呼び出します。これにより、スキーマが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)>'
モデル(簡略化)
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 (簡略化)
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
アップデート
チーズウィーゼルは解決策を見つけました。単体テスト Price.latest_prices_for_purchaser は、Organization#suppliers_for_purchaser を次のように変更した場合にのみ機能しました。
partners.joins(:organization_role).where('organization_roles.name = ?', "supplier")