はじめに
こんにちは、株式会社TOKOSのナオキです!
皆さんはコードの可読性を気にした設計が出来ていますか?
「とりあえず思い通りに動けばいいや」と思いコントローラーにロジックを詰め込んだり、同じ処理をコントローラー毎に記述していませんか?
もしそのような方がいましたら今回解説するコールバックを使用し、メソッドの複雑度をさげ可読性が上がるよう設計していきましょう!
- Rails初学者の方
- コードの可読性を上げたいと思っている方
コールバックとは
Railsガイドより
オブジェクトのライフサイクルの特定の瞬間に呼び出されるメソッドのことです。
コールバックを使えば、Active Recordオブジェクトがデータベースで初期化・作成・保存・更新・削除・バリデーション・読み込みのたびに実行されるコードを記述できます。
詳細に知りたい方は以下を参照してください!
よく使用されるコールバックには以下のようなものがあります。
コールバックの種類 | 説明 |
---|---|
before_save | レコードが保存される前に実行 |
after_save | レコードが保存された後に実行 |
before_create | レコードが作成される前に実行 |
after_create | レコードが作成された後に実行 |
before_destroy | レコードが削除される前に実行 |
after_destroy | レコードが削除された後に実行 |
基本的な使用方法
コールバックを使用する際は、モデルクラス内で上記で紹介したようなコールバックを登録し、実行させたいメソッドを受け取ります。
以下のサンプルコードは、保存前に名前の余分な空白をなくす処理です。
保存時にデータを一貫した形式にしたい場合、このように記述する方法もあります。
class User < ApplicationRecord
before_save :normalize_name
private
def normalize_name
self.name = name.strip
end
end
このようにコールバックを登録することで、User
のレコードが保存されるたびにnormalize_name
メソッドが実行されます。User
のレコードを保存するという処理を複数箇所で行っていた場合、本来であればその使用箇所全てに同じ記述をしなくてはいけません。
しかし、コールバックを登録しておけば他の箇所でその処理の記述をしなくても済みます。
それによりメソッドの記述量が減り、可読性をあげることができるのです!
コールバックの登録ではメソッド以外にも以下のようにブロックを受け取ることができます。
コールバックしたいロジックが短い時などはこちらを使用してみてもいいかもしれません。
class User < ApplicationRecord
before_save do
self.name = name.strip
end
end
例としてサンプルコードをもう一つあげます。
以下はユーザーを作成した後にそのユーザーに対してメールを送る処理です。
class User < ApplicationRecord
before_save :normalize_name
private
def normalize_name
self.name = name.strip
end
end
基本的にはこのような感じで使用していきます!
コールバックの応用
特定の条件下でのみコールバックを実行することも可能です。
以下はif
を使用しユーザー作成後、email
が存在する場合にのみメール送信をします。if
の逆であるunless
を使用することも可能です!
class User < ApplicationRecord
after_create :send_email, if: -> { email.present? }
private
def send_email
UserMailer.welcome_email(self).deliver_now
end
end
また、以下のようにif, unless
を併用してコールバック登録をすることも出来ます。
class User < ApplicationRecord
after_create :send_email, if: -> { email.present? }, unless: -> { status == guest }
private
def send_email
UserMailer.welcome_email(self).deliver_now
end
end
上記はユーザー作成時、email
が存在しなおかつ、status
がguest
でないユーザーに対してメール送信を行います。
コールバックのスキップ
以下のメソッドを使用するとコールバックはスキップされます。
これはバリデーションも同様です!
delete
delete_all
update_column
update_all
upsert
スキップされるメソッドがあることを知らないと、なぜコールバックが実行されないのかで詰まってしまう可能性があります。
なので、コールバックがうまく実行されない場合は使用しているメソッドがスキップされるメソッドでないかを確認しましょう!
上記以外にもスキップされるメソッドがあるので詳しく知りたい方は、記事の上部に貼ってあるRailsガイドを参照してください。
通常はコールバックを行いたいが、例外的にスキップさせたい場合もあるかと思います。
そのような場合にはattr_accessor
を使用する方法があります!
以下のようにattr_accessor
で、コールバックをスキップするかどうかを管理するためのフラグを追加し、そのフラグの状態でコールバックの処理を実行するかどうか制御します。
class User < ApplicationRecord
attr_accessor :skip_normalize_name # 追加
before_save :normalize_name, unless: -> { skip_normalize_name }
private
def normalize_name
self.name = name.strip
end
end
上記のように設定したらあとは以下のように使用するだけです!
通常時の保存の場合:
user = User.new(name: " 田中太郎")
user.save
puts user.name
# => "田中太郎"
コールバックをスキップしたい場合:
user = User.new(name: " 田中太郎")
user.skip_normalize_name = true
user.save
puts user.name
# => " 田中太郎"
このようにattr_accessor
を使用したらコールバックの制御を簡単に行えます。
スキップ処理が必要な場合のみ適切に使用することが大切になります!
おわりに
今回はコールバックについて解説をしました!
コールバックは、モデルのライフサイクルに特定の処理を組み込む便利な機能ですが、使い方を誤るとコードが複雑化し、デバックが難しくなってしまいます。
本記事で紹介した、特定の条件下でのコールバック実行やスキップ機能をうまく活用し、必要な箇所にだけ適切にコールバックを取り入れることが大切になります!
ぜひ、この記事を参考に、プロジェクトでコールバックを効果的に活用してみてください!