awesome_nested_setをv3.1.4に更新したらdefault_scopeが有効になった

# はじめに

ツリー構造を実装するときに、Gem使ってたりしませんか？
ツリーの実装自体は一般的な考え方の範疇だけど、独自に実装するのはコストが〜、車輪の再開発〜みたいなところありますよね？

私も例に漏れず、[awesome_nested_set](https://github.com/collectiveidea/awesome_nested_set) というGemにお世話になっているのですが、Gemのversionを更新するタイミングで、 `default_scope` の挙動が変わることを知ったので記事にしておきます。

v3.1.1の時点で影響が発生していたようです。
いまさらかーい！みたいな感想もあるかと思いますが、誰かの助けになれば幸いです。

<img width="962" alt="default_scopeが有効になったversion" src="https://qiita-image-store.s3.amazonaws.com/0/180193/b3d1c3f1-bfff-b87f-3ec5-5a32aec96898.png">



# 対象Gemと変更

【対象Gem】 
[awesome_nested_set](https://github.com/collectiveidea/awesome_nested_set)

【変更があったversion】
 [3.1.0](https://github.com/collectiveidea/awesome_nested_set/commit/b5be38acae70a5715e37a75535ca25cc6c097d0f) （3.1.1で `default_scope` に関するバグフィックス来てるっぽいですが）

【情報共有したい変更点】
Gem側の実装で `unscoped` が外されました。
つまり、 `default_scope` が実装されているモデルで使われるとクエリが変わります。

[具体的な変更内容](https://github.com/collectiveidea/awesome_nested_set/commit/b5be38acae70a5715e37a75535ca25cc6c097d0f) は、コミットの差分みれば理解に難しくないかと思います。
この影響は [CHANGELOG](https://github.com/collectiveidea/awesome_nested_set/blob/master/CHANGELOG) で気が付けます。

## 具体的な影響の確認

例えばこんなモデルに、廃止カテゴリを論理削除する `removed_flag` というカラムがあった場合、発行されるクエリに変化があります。

```category.rb

# == Schema Information
#
# Table name: categories
#
#  id                    :integer          not null, primary key
#  name                  :string(64)       not null
#  parent_id             :integer
#  lft                   :integer
#  rgt                   :integer
#  removed_flag          :boolean          default(FALSE), not null
#  created_at            :datetime
#  updated_at            :datetime


Class Category < ActiveRecord::Base
   default_scope -> {
     where(categories: { removed_flag: false }).order('categories.lft')
   }
   ...
end
```

### v3.0.3の場合

`Category` モデルに設定されている `default_scope` は、 `Category.root.leaves` でレコードを引っ張ってくる際には無効になっていることがわかる。（[v3.0.3時点では `unscoped ` されているため](https://github.com/collectiveidea/awesome_nested_set/commit/b5be38acae70a5715e37a75535ca25cc6c097d0f)）

```
> pry(main)> Category.root.leaves
  Category Load (0.8ms)     # 1件目のクエリ
    SELECT
      `categories`.* 
    FROM 
      `categories`
    WHERE
      `categories`.`removed_flag` = 0 AND
      `categories`.`parent_id` IS NULL
    ORDER BY ...           # ※ORDER BYは省略

  Category Load (1.3ms)    # 2件目のクエリ
    SELECT
      `categories`.* 
    FROM
     `categories` 
    WHERE
      (`categories`.`lft` >= 1) AND ...
    ORDER BY ...
```

### v3.1.4の場合

2件目のクエリ( `leaves` )に、`default_scope` の `removed_flag = 0` が発行されています。
発行されるクエリが変わるので、レコードの発生状況によっては影響が大きいかと思います。
場合によっては、実装直したり設計し直したりが必要になるかもしれません。

```
> Category.root.leaves
  Category Load (0.8ms)   # 1件目のクエリ
    SELECT
　　　　　　　  `categories`.* 
　　　　  FROM
　　　　　   `categories`
　　　　  WHERE
　　　　　　  `categories`.`removed_flag` = 0 AND
　　　　   `categories`.`parent_id` IS NULL
 　　  ORDER BY ...

    Category Load (1.2ms)  # 2件目のクエリ
      SELECT `categories`.* FROM
        `categories`
      WHERE 
        `categories`.`removed_flag` = 0 AND   # ←ここdefault_scopeの影響
        (`categories`.`lft` >= 1) AND ...
    ORDER BY ...
```


# その他

過去に `default_scope` を ~~disった~~ 使った感想を記事にしたんですが、因果なものです。
不備やご指摘あればコメントいただけたらと思います:bow: