コールバックによる制御

# コールバックとは
>ActiveRecordでは、`レコードを作成して保存する一連の流れの間の様々な箇所で任意の処理を差し込め`ます。こういった特定の処理に引っ掛けて別の処理を呼ぶことをコールバックと言います。ActiveRecordのコールバックを上手に活かすことで、以下のメリットが生まれます。
>* 前処理、後処理などを宣言的にかける
>* 必ず保存後に行いたい処理がある時に、実行漏れを防ぐことができる

```rb
 validates :price, numericality: { greater_than_or_equal_to: 0}
  before_validation do
    self.name = self.name.gsub(/Cat/) do |matched|
      "lovely #{matched}"
    end
  end
# コメントアウトしている部分のようにも書ける
  # before_validation :add_lovely_to_cat
  #
  # def add_love_to_cat
  #   self.name = self.name.gsub(/Cat/) do |matched|
  #     "lovely #{matched}"
  #   end
  # end
```

```rb
irb(main):003:0> Book.create(name: "We Love Cat", published_on: "hogehoge", pric
e: 999)
  TRANSACTION (0.2ms)  SAVEPOINT active_record_1
  Book Create (17.5ms)  INSERT INTO `books` (`name`, `published_on`, `price`, `created_at`, `updated_at`) VALUES ('We Love lovely Cat', NULL, 999, '2024-12-12 05:45:44.039946', '2024-12-12 05:45:44.039946')
  TRANSACTION (0.2ms)  RELEASE SAVEPOINT active_record_1
=>
#<Book:0x000000010dd78bc0
 id: 6,
 name: "We Love lovely Cat",
 published_on: nil,
 price: 999,
 created_at: Thu, 12 Dec 2024 05:45:44.039946000 UTC +00:00,
 updated_at: Thu, 12 Dec 2024 05:45:44.039946000 UTC +00:00>
 ```

 >Bookモデルを削除した際に、削除されたデータの内容をログに書き込む処理が動作するようにします。

```rb
after_destroy do
    Rails.logger.info "Book is deleted: #{self.attributes}"
  end
```
```rb
irb(main):004:0> book.destroy
  TRANSACTION (0.3ms)  SAVEPOINT active_record_1
  Book Destroy (4.0ms)  DELETE FROM `books` WHERE `books`.`id` = 7
Book is deleted: {"id"=>7, "name"=>"We Love lovely Cat", "published_on"=>nil, "price"=>999, "created_at"=>Thu, 12 Dec 2024 05:50:26.035256000 UTC +00:00, "updated_at"=>Thu, 12 Dec 2024 05:50:26.035256000 UTC +00:00}
  TRANSACTION (0.2ms)  RELEASE SAVEPOINT active_record_1
=>
#<Book:0x0000000108fd8050
 id: 7,
 name: "We Love lovely Cat",
 published_on: nil,
 price: 999,
 created_at: Thu, 12 Dec 2024 05:50:26.035256000 UTC +00:00,
 updated_at: Thu, 12 Dec 2024 05:50:26.035256000 UTC +00:00>
 ```

 # コールバックポイントの名前で発火時点がきまる
 >データ更新系のコールバックポイントを表2.5に示します。「＊_validatio」系は文字通りバリデーション処理の前後に「＊＿create」「＊_update」「*_destroy」系はデータが実際にDBへ書き込まれる前後でそれぞれ発火
 するコールバックです
 この他に、after_initializeとafter_findというコールバックポイントがあります。
 after_initializ絵はActiveRecord::Base(あるいはApplicationRecord)を継承したモデルがインスタンス化したタイミングで必ず実行されます。
...
after_findはfind系のメソッド、具体的には「first」「last」「find」「find＿by」によってモデルのインスタンス生成した場合にしか実行されません。

# :if, :unlessによって条件でコールバックを行う
>:if,:unlessというオプションによって、特定の条件を満たした場合のみ実行するコールバックを実装することが可能です
```rb
after_destroy if: :high_price? do
    Rails.logger.warn "Book with high price is deleted: #{self.attributes}"
    Rails.logger.warn "Please check!!"
  end

  def high_price?
    price >= 5000
  end
```

```rb
irb(main):006:0> book.destroy
  TRANSACTION (0.5ms)  SAVEPOINT active_record_1
  Book Destroy (0.5ms)  DELETE FROM `books` WHERE `books`.`id` = 8
Book is deleted: {"id"=>8, "name"=>"We Love lovely Cat", "published_on"=>nil, "price"=>9999, "created_at"=>Thu, 12 Dec 2024 08:46:58.018858000 UTC +00:00, "updated_at"=>Thu, 12 Dec 2024 08:46:58.018858000 UTC +00:00}
Book with high price is deleted: {"id"=>8, "name"=>"We Love lovely Cat", "published_on"=>nil, "price"=>9999, "created_at"=>Thu, 12 Dec 2024 08:46:58.018858000 UTC +00:00, "updated_at"=>Thu, 12 Dec 2024 08:46:58.018858000 UTC +00:00}
Please check!!
  TRANSACTION (0.3ms)  RELEASE SAVEPOINT active_record_1
=>
#<Book:0x000000010ee02888
 id: 8,
 name: "We Love lovely Cat",
 published_on: nil,
 price: 9999,
 created_at: Thu, 12 Dec 2024 08:46:58.018858000 UTC +00:00,
 updated_at: Thu, 12 Dec 2024 08:46:58.018858000 UTC +00:00>
irb(main):007:0>
```

https://gihyo.jp/book/2020/978-4-297-11462-6