Railsのdefault_scopeは悪ではない。

## はじめに
default_scopeでググるとdefault_scopeは悪なので使うべきじゃないみたいな記事が多いのだけど、その後のアップデート情報が少なく、正しく使えば便利なのでその誤解を解きたい

Rails 5.1.6
Ruby 2.4.3
で確認

## use case
質問投稿サイトを例にすると、
質問モデルがあり、ステータスとして表示、非表示のものがあるとします。
基本的にはステータスが表示のものだけを表示する。ただし、投稿者のMyPageや管理画面では全部を表示したい。
この場合、非表示のものが間違って表示されてはいけないのでステータスが表示の条件を当てるようにするが、毎回指定するのは面倒だし、漏れが出てしまう可能性も十分にあります。
そこでdefault_scopeを使います。
挙動としては、デフォルトでは表示のものだけを取得で、指定された場合だけその条件を外すようにする。

モデル例は以下のようになります。

```rb

class Question < ApplicationRecord
  enum status: {active: 1,inactive: 10}
  default_scope { where(status: :active) }
end
```


デフォルトでのSQLは以下のようになる

```rb

irb(main):067:0> Question.all.to_sql
=> "SELECT `questions`.* FROM `questions` WHERE `questions`.`status` = 1"
```

## default_scopeの解除
default_scopeの解除でunscopedがよく記事に出てますが、これを使うとたしかに危険です。

```rb

irb(main):068:0> Question.unscoped.to_sql
=> "SELECT `questions`.* FROM `questions`"
```
一見いいようにみえますが、例えばacts_as_paranoidを使っていたとします。
モデルにacts_as_paranoidを追加

```rb

class Question < ApplicationRecord
  acts_as_paranoid
  enum status: {active: 1,inactive: 10}
  default_scope { where(status: :active) }
end
```

デフォルトでのSQLは以下のようになる

```rb

irb(main):070:0> Question.all.to_sql
=> "SELECT `questions`.* FROM `questions` WHERE `questions`.`deleted_at` IS NULL AND `questions`.`status` = 1"
```

unscopedすると。。

```ruby
irb(main):072:0> Question.unscoped.to_sql
=> "SELECT `questions`.* FROM `questions`"
```

deleted_at IS NULL まで解除されてしまっています。

### unscopeを使う

```rb

class Question < ApplicationRecord
  acts_as_paranoid
  enum status: {active: 1,inactive: 10}
  default_scope { where(status: :active) }
  scope :with_inactive, ->{ unscope(where: :status) } # ←これ追加
end
```

unscopeを利用してstatusの条件を外します。
結果は以下のように

```ruby
irb(main):074:0> Question.with_inactive.to_sql
=> "SELECT `questions`.* FROM `questions` WHERE `questions`.`deleted_at` IS NULL"
```

deleted_at IS NULLの条件はそのままに、status: :activeだけ外れています。

## default_scopeでorderを指定している場合は？
default_scopeでorderを指定するケースはあんまり思い浮かばないですが、同じように以下のようにすると外すことができます
モデル

```ruby
class Question < ApplicationRecord
  acts_as_paranoid
  enum status: {active: 1,inactive: 10}
  default_scope { where(status: :active) }
  default_scope { order(created_at: :desc) } # ←これ追加
end
```

デフォルトでorder byがつく

```ruby
irb(main):078:0> Question.all.to_sql
=> "SELECT `questions`.* FROM `questions` WHERE `questions`.`deleted_at` IS NULL AND `questions`.`status` = 1 ORDER BY `questions`.`created_at` DESC"
```

そこでunscope(:order)する。※unscopeにhashが渡せるのはwhereだけ
これでorder byが外れます

```ruby
irb(main):087:0>  Question.unscope(:order).to_sql
=> "SELECT `questions`.* FROM `questions` WHERE `questions`.`deleted_at` IS NULL AND `questions`.`status` = 1"
```

その他にも指定できます
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-unscope

## モデルをイニシャライズするときにデフォルト値が入ってしまう
以下のようにしているとnewしたときにデフォルト値が自動で入ってしまう

```ruby
class Question < ApplicationRecord
  enum status: {active: 1,inactive: 10}
  default_scope { where(status: :active) }
end
```

```ruby
irb(main):088:0> Question.new
=> #<Question id: nil, user_id: nil, status: "active", ...>
```

unscopeしてあげれば解決しますが、ちょっと面倒ですね

```ruby
irb(main):105:0> Question.unscope(where: :status).new
=> #<Question id: nil, user_id: nil, status: nil, 
```

attributeでdefault設定すればいけるかなとおもいきや、だめだった

```ruby
class Question < ApplicationRecord
  enum status: {active: 1,inactive: 10}
  default_scope { where(status: :active) }
  attribute :status, :integer, default: -> { :inactive } # ←これ追加してもdefaultは:active
end
```

ここはデフォルト値と違う値を入れたい場合はnewの後に設定してあげるでいいんじゃないかな。

## 終わりに
default_scopeは便利なので使うといいよ。ただしunscopedではなくunscopeを利用