default_scope の 被害報告
2015/03/28 minami.rb 最初で最後のLT大会
無量井 健(@muryoimpl)
https://www.flickr.com/photos/jakerust/16827350035
自己紹介
• 無量井 健(むりょうい けん)
• 永和システムマネジメント 7ヶ月目
• Ruby関西, 関西Ruby会議04・05, るびま etc
• 休日は、低機動型寝たきり二時間サスペンス廃人
皆さんご存知だと おもいますが
https://www.flickr.com/photos/aruarian/2626408619
https://www.flickr.com/photos/aruarian/2626408619
default_scope
default_scopeclass Item < ActiveRecord::Base default_scope -> { order(:order_no) } end
irb(main)> Item.find(1) SELECT "items".* FROM “items" WHERE "items"."id" = ? ORDER BY “items"."order_no" DESC LIMIT 1 [["id", 1]]
https://www.flickr.com/photos/lintmachine/3652702115
何もしなくても 勝手に
条件がつきますねhttps://www.flickr.com/photos/aruarian/2626408619
便利ですね
https://www.flickr.com/photos/aruarian/2626408619
default_scope の条件外す方法 ありますね
https://www.flickr.com/photos/aruarian/2626408619
https://www.flickr.com/photos/lintmachine/3652702115
unscopedirb(main)> Item.unscoped.find(1) SELECT "items".* FROM “items" WHERE "items"."id" = ? DESC LIMIT 1 [["id", 1]]
irb(main)> Item.unscoped { Item.find(1) } SELECT "items".* FROM “items" WHERE "items"."id" = ? LIMIT 1 [["id", 1]]
https://www.flickr.com/photos/lintmachine/3652702115
exceptirb(main)> Item.except(:order).find(1) SELECT "items".* FROM “items" WHERE "items"."id" = ? DESC LIMIT 1 [["id", 1]]
https://www.flickr.com/photos/lintmachine/3652702115
unscopeirb(main)> Item.unscope(:order).find(1) SELECT "items".* FROM “items" WHERE "items"."id" = ? DESC LIMIT 1 [["id", 1]]
外れましたね?
https://www.flickr.com/photos/aruarian/2626408619
調べると だいたいこういう例が
載っていますhttps://www.flickr.com/photos/aruarian/2626408619
さてhttps://www.flickr.com/photos/aruarian/2626408619
結合とかしてたら どうですかね?
https://www.flickr.com/photos/aruarian/2626408619
includesしてみるぞ
class Author < ActiveRecord::Base has_many :posts
default_scope -> { where(status: :ok) } end
class Post < ActiveRecord::Base belongs_to :author end
https://www.flickr.com/photos/lintmachine/3652702115
https://www.flickr.com/photos/lintmachine/3652702115
includesしてみるぞirb(main)> Post.includes(:author) .where(status: :ok) .where(authors: {name: ‘a’}) SELECT "posts"."id" AS t0_r0, … FROM "posts" LEFT OUTER JOIN "authors" ON "authors"."id" = “posts"."author_id" AND "authors"."status" = ? WHERE "authors"."name" = ? [["status", 1], ["name", "a"]]
https://www.flickr.com/photos/lintmachine/3652702115
unscopedirb(main)> Author.unscoped { Post.includes(:author) .where(status: :ok) .where(authors: {name: ‘a’}) } SELECT "posts"."id" AS t0_r0, … FROM "posts" LEFT OUTER JOIN "authors" ON "authors"."id" = “posts"."author_id" AND "authors"."status" = ? WHERE "authors"."name" = ? [["status", 1], ["name", "a"]]
外れない!https://www.flickr.com/photos/aruarian/2626408619
https://www.flickr.com/photos/lintmachine/3652702115
exceptirb(main)> Post.includes(:author).except(:where) .where(status: :ok) .where(authors: {name: ‘a’}) SELECT "posts"."id" AS t0_r0, … FROM "posts" LEFT OUTER JOIN "authors" ON "authors"."id" = “posts"."author_id" AND "authors"."status" = ? WHERE "authors"."name" = ? [["status", 1], ["name", "a"]]
そもそも ON句だし…
https://www.flickr.com/photos/aruarian/2626408619
https://www.flickr.com/photos/lintmachine/3652702115
exceptirb(main)> Post.includes(:author) .except(on: :status) #ないよね…無視される .where(status: :ok) .where(authors: {name: ‘a’}) SELECT "posts"."id" AS t0_r0, … FROM "posts" LEFT OUTER JOIN "authors" ON "authors"."id" = “posts"."author_id" AND "authors"."status" = ? WHERE "authors"."name" = ? [["status", 1], ["name", "a"]]
https://www.flickr.com/photos/lintmachine/3652702115
unscopeirb(main)> Post.includes(:author) .unscope(on: :status) #ないよね… .where(status: :ok) .where(authors: {name: ‘a’})
ArgumentError: Hash arguments in .unscope(*args) must have :where as the key.
https://www.flickr.com/photos/lintmachine/3652702115
unscopeirb(main)> Post.includes(:author) .unscope(where: :status) .where(status: :ok) .where(authors: {name: ‘a’}) SELECT "posts"."id" AS t0_r0 … FROM "posts" LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id" AND "authors"."status" = ? WHERE "authors"."name" = ? [["status", 1], ["name", "a"]]
別の関連つくって…class Author < ActiveRecord::Base has_many :posts
default_scope -> { where(status: :ok) } end
class Post < ActiveRecord::Base belongs_to :author belongs_to :unscoped_author, -> { unscope(where: :status) }, foreign_key: :author_id, class_name: ‘Author’ end https://www.flickr.com/photos/lintmachine/3652702115
https://www.flickr.com/photos/lintmachine/3652702115
別の関連つくって…irb(main)> Post.includes(:unscoped_author) .where(status: :ok) .where(authors: {name: ‘a’}) SELECT "posts"."id" AS t0_r0, … FROM "posts" LEFT OUTER JOIN "authors" ON "authors"."id" = “posts"."author_id" AND "authors"."status" = ? WHERE "authors"."name" = ? [["status", 1], ["name", "a"]]
やはり 外れない!
https://www.flickr.com/photos/aruarian/2626408619
https://www.flickr.com/photos/alvarez-tostado/363243449
マ”マ”ーーー
https://www.flickr.com/photos/alvarez-tostado/363243449
ということで…
https://www.flickr.com/photos/alvarez-tostado/363243449
泣きながら こうした…
default_scopes =[]class Author < ActiveRecord::Base has_many :posts
default_scope -> { where(status: :ok) } end
class UnscopedAuthor < Author # ↓ここがポイント self.default_scopes = [] end
class Post < ActiveRecord::Base belongs_to :author belongs_to :unscoped_author, foreign_key :author_id end https://www.flickr.com/photos/lintmachine/3652702115
default_scopeさん…• こんな罠がありました… • 単一モデルしか検索しない間は便利さしか感じないかもしれませんが…SQL的にJOINすることになると面倒なことになります(なりました)
• 少し面倒なクエリを考えるときに直面するのですよ…この問題
• 後悔しないように、scopeを毎回つけるか設計を見直すほうが良いと思います
https://www.flickr.com/photos/71508688@N00/5139944772