ポリモーフィックを用いたサブクエリが誤った結果を返していた。
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?
コメント