ハッカーを目指す白Tのブログ

夏は白のTシャツを着ています。ラジオが好きです。(ラジオネーム: 隠れキリジダン)

Railsのコールバックについてまとめてみた

Railsのコールバックとは、一体何なんだろうか。今回は、Railsのコールバックの概要を解説する。

1.コールバックとは何か

Railsのコールバックは、オブジェクトの状態が変わるとき、すなわちオブジェクトが生成、更新、破壊されるときや、バリデーションを実行するときの前後に共通の処理を追加する仕組みである。これはモデル層で指定でき、処理を共通化することによって、モデルの一貫性を保て、またコード量を減らすことができる。

2. 2種類のコールバックの定義の仕方

モデルにて、コールバックを指定する方法は、2つある。
まず、最も一般的な方法がprivateでメソッドを切って、それを呼び出す方法。

class User < ActiveRecord::Base
  validates :login, :email, presence: true            #validationの指定
 
  before_validation :ensure_login_has_a_value  #callbackの指定
 
  protected
    def ensure_login_has_a_value
      if login.nil?
        self.login = email unless email.blank?
      end
    end
end

次に、コールバックにブロックを渡す方法。

class User < ActiveRecord::Base
  validates :login, :email, presence: true
 
  before_create do
    self.name = login.capitalize if name.blank?
  end
end

さらに、コールバックの定義を、オブジェクトのライフサイクル(オブジェクトの生成、更新、削除等)の中の一部の処理に関してのみ行うことができる。それは、以下のようにonオプションに指定する。

class User < ActiveRecord::Base
  before_validation :normalize_name, on: :create #createアクションにのみ、コールバックが適用される。
 
  # :on に配列も引き渡せる。
  after_validation :set_location, on: [ :create, :update ]
 
  protected
    def normalize_name
      self.name = self.name.downcase.titleize
    end
 
    def set_location
      self.location = LocationService.query(self)
    end
end

3. 使用できるコールバック一覧

まず、オブジェクトのライフサイクル、すなわちオブジェクトの生成、更新、削除の各過程において使用可能なコールバックを、呼び出される順番に、以下並べる。


オブジェクトの生成(create)


before_validation

after_validation

before_save

around_save

before_create

around_create

after_create

after_save


オブジェクトの更新(update)


before_validation

after_validation

before_save

around_save

before_update

around_update

after_update

after_save


オブジェクトの削除(destroy)


before_destroy

around_destroy

after_destroy

以上の、オブジェクトのライフサイクルに関わるコールバックの他にもいくつかのコールバックが存在する。
・オブジェクトがinitializeされたあと => after_initialize
  オブジェクトに対して、newメソッドが呼ばれたときや、データベースからレコードがloadされたとき(データベースのレコードがインスタンス化されたとき)等、オブジェクトがinitializeされた後に処理を追加するコールバック。

・データベースからレコードがloadされたあと => after_find

ただし、after_initializeとafter_findが両方定義されているとき、after_findが先に呼び出される。

class User < ActiveRecord::Base
  after_initialize do |user|
    puts "after_initializeを呼び出しました"
  end
 
  after_find do |user|
    puts "after_findを呼び出しました"
  end
end
 
>> User.new
after_initializeを呼び出しました
=> #<User id: nil>
 
>> User.first
after_findを呼び出しました
after_initializeを呼び出しました
=> #<User id: 1>

・オブジェクトにtouchメソッドが呼び出されたあと => after_touch
  オブジェクトのupdated_atカラムを現在時刻に更新するtouchメソッドが呼び出されるあとに処理を追加するコールバック。

参照URL:Active Record Callbacks — Ruby on Rails Guides

以上