ActiveRecord attribute methodまとめ（その①: BeforeTypeCast編）

# はじめに
何かとやってくれる<a href="https://railsguides.jp/active_record_basics.html">ActiveRecord</a>。その機能を十分に使いこなせていますか？
~~僕は、使いこなせてません！笑~~
今回は、そんなActiveRecordのattribute methodのうち、BeforeTypeCastのメソッドについてまとめていきます。
（2022年3月時点。Rails7.0対応。）

# 検証環境
以下のschemaとmodelに基づいて検証を行なっています。

``` db/schema.rb
create_table "todos", charset: "utf8mb4", force: :cascade do |t|
  t.string "title"
  t.datetime "schedule_at"
  t.integer "status"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end
```
``` app/model/todo.rb
class Todo < ApplicationRecord
  enum status: { not_yet: 0, complete: 1, in_progress: 2, cancel: 3 }
end
```

# BeforeTypeCast
型キャストされる前の値を取得するメソッド群です。
enumを使ったり、独自にattributeを定義して使ったりする時にはお世話になります。

## attributes_before_type_cast
attributes_before_type_castを用いると、型キャスト前の情報でattributeのハッシュが取得できます。

``` Ruby
todo = Todo.new(status: :complete, schedule_at: '2022-02-22 22:22:22')
todo.attributes 
#=> {..., "schedule_at"=>Tue, 22 Feb 2022 22:22:22.000000000 JST +09:00, "status"=>"complete", ...}
todo.attributes_before_type_cast
#=> {..., "schedule_at"=>"2022-02-22 22:22:22", "status"=>:complete, ...}
```
## [attribute名]_before_type_cast
[attribute名]_before_type_castで特定のattributeの型キャスト前の値が取得可能です。

``` Ruby
todo.schedule_at #=> Tue, 22 Feb 2022 22:22:22.000000000 JST +09:00
todo.schedule_at_before_type_cast #=> "2022-02-22 22:22:22"
```

## attributes_for_database
attributes_for_databaseは、データベースに入る型にキャストされたatttibuteのハッシュを返します。
このメソッドはRails7.0から追加されました。

``` Ruby
todo = Todo.new(status: :complete, schedule_at: '2022-02-22 22:22:22')
todo.attributes
#=> {..., "schedule_at"=>Tue, 22 Feb 2022 22:22:22.000000000 JST +09:00, "status"=>"complete", ...}
todo.attributes_for_database
#=> {..., "schedule_at"=>"2022-02-22 22:22:22 +0900", "status"=>1, ...}
```

## [attribute名]_for_database
[attribute名]_for_databaseを用いると、特定のattributeの値をデータベースに入る型で取得できます。
attributes_for_databaseと同様に、Rails7.0から追加されたのかと思いきや、Rails6.1からこっそり存在していました。

``` Ruby
todo.status #=> "complete"
todo.status_for_database #=> 1
```

下の例のように、入ってくる値がデータベースの型の時、_before_type_cast, _for_databaseの両方とも同じ値を返しますが、動作が同じものと誤解しないように注意してください。

``` Ruby
todo = Todo.new(status: 2)
todo.status #=> "in_progress"
todo.status_before_type_cast #=> 2
todo.status_for_database #=> 2
```

## read_attribute_before_type_cast
[attribute名]_before_type_castと同様に、指定したattributeの型キャスト前の値を返します。
[attribute名]_before_type_castの場合は、存在しないattributeに対して実行するとNoMethodErrorの例外を吐きますが、read_attribute_before_type_castでは、存在しないattribute名を指定すると、Exceptionではなくnilを返します。

``` Ruby
todo = Todo.new(status: :complete, schedule_at: '2022-02-22 22:22:22')
todo.read_attribute(:status) #=> "complete"
todo.read_attribute_before_type_cast(:status) #=> :complete

# 存在しないattribute名を指定すると、nilを返す
todo.read_attribute_before_type_cast(:no_attribute)#=> nil

# 存在しないattributeに対して実行するとNoMethodErrorの例外を吐く
todo.no_attribute_before_type_cast
#=> NoMethodError (undefined method `no_attribute_before_type_cast' for ....
```

# おわりに
今回は、BeforeTypeCastについてまとめていきました。
普段あまり意識せずに使っているメソッドも、しっかり考えてみると奥深いものですね。

その他のメソッドについては、別記事でまとめています。↓↓
[ActiveRecord attribute methodまとめ（その②: Dirty編）](https://qiita.com/maabow/items/0a5a228fb6c1447877e0)
[Active Record attribute methodまとめ（その③: PrimaryKey編）](https://qiita.com/maabow/items/012c473312961ce7e060)
[Active Record attribute methodまとめ（その④: Query, Read, Write編）](https://qiita.com/maabow/items/3d704bde6c4531bbb0ac)


# 参考
- <a href="https://github.com/rails/rails/tree/main/activerecord/lib/active_record/attribute_methods">rails github</a>
- <a href="https://railsguides.jp/">Railsガイド</a>
- <a href="https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/BeforeTypeCast.html">ActiveRecord::AttributeMethods::BeforeTypeCast</a>