ポリモーフィックを用いたサブクエリが誤った結果を返していた

ポリモーフィックを用いたサブクエリが誤った結果を返していた。

Fix polymorphic association subquery by lazaronixon · Pull Request #48362 · rails/rails
Motivation / Background Fix where on association with has_one/has_many polymorphic relations. Before: Treasure.where(price_estimates: PriceEstimate.all) #=> ...

再現

プルリクエストより

require "active_record"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Schema.define do
  create_table :pins do |t|
    t.string :code, null: false
  end
  create_table :cards do |t|
  end
  create_table :access_tools do |t|
    t.references :item, polymorphic: true
  end
end

class Pin < ActiveRecord::Base
  has_one :access_tool, as: :item
end

class Card < ActiveRecord::Base
  has_one :access_tool, as: :item
end

class AccessTool < ActiveRecord::Base
  belongs_to :item, polymorphic: true
end

Pin.create!(code: "1111")
AccessTool.create!(item: Card.create!)
AccessTool.create!(item: Pin.create!(code: "2222"))

Pin.where(access_tool: AccessTool.all).count

ポリモーフィック関連付けでこんな書き方ができるのを知らなかった。

AccessTool.create!(item: Card.create!)

期待されている挙動

AccessToolにひもづく Pin は1つだけなので、それのみを返すはず。

Pin.where(access_tool: AccessTool.all).count
#=> [#<Pin:0x00007fc026b05e30 id: 3, code: "2222">]

実際の挙動

AccessTool に紐づいていない Pin レコードまで返却されてしまう。

Pin.where(access_tool: AccessTool.all).count
#=> [#<Pin:0x00007fc026b04d50 id: 1, code: "1111">;, #<Pin:0x00007fc026b05e30 id: 3, code: "2222">]

生成しているクエリ

SELECT "pins".* FROM "pins" WHERE "pins"."id" IN (
  SELECT "access_tools"."item_id" FROM "access_tools"
)
> AccessTool.all
=>
[#<AccessTool:0x00007fa8898b60d0 id: 1, item_type: "Card", item_id: 1>,
 #<AccessTool:0x00007fa8898b5f40 id: 2, item_type: "Pin", item_id: 2>]

であるため、item_id = 1は本来Cardを指定しているはずだがid=1のPinまで取得してきてしまう。

期待される正しいクエリ

サブクエリ内でitem_typeを指定する。

SELECT "pins".* FROM "pins" WHERE "pins"."id" IN (
  SELECT "access_tools"."item_id" FROM "access_tools" WHERE item_type = "pin"
)

主な変更箇所

+ relation = relation.where(primary_type => polymorphic_name) if polymorphic_clause?

コメント

タイトルとURLをコピーしました