【パーフェクトRails】コールバックをクラスに分離する
目的
パーフェクトRuby on Railsの9章の9−2「複雑なバリデーションとコールバックを整理する」を読んでいて コールバックをクラスに分離する場面ややり方がよくわからなかったのでまとめる。
- 作者: すがわらまさのり,前島真一,近藤宇智朗,橋立友宏
- 出版社/メーカー: 技術評論社
- 発売日: 2014/06/06
- メディア: 大型本
- この商品を含むブログ (8件) を見る
はじめにさらっと今回の主張だけ述べて、本編に突入します。
コールバックをクラスに分離するのは必要?
- あってもいいとは思うけど、作る機会は少ないかも。
作る場合はapp/models
かapp/services
に入れておけばいいかな
「コールバックをクラスに分離する」とは何か?
Railsのドキュメントにあったソースをそのまま載せてしまいます。
class BankAccount < ActiveRecord::Base before_save EncryptionWrapper.new("credit_card_number") after_save EncryptionWrapper.new("credit_card_number") after_initialize EncryptionWrapper.new("credit_card_number") end class EncryptionWrapper def initialize(attribute) @attribute = attribute end def before_save(record) record.send("#{@attribute}=", encrypt(record.send("#{@attribute}"))) end def after_save(record) record.send("#{@attribute}=", decrypt(record.send("#{@attribute}"))) end alias_method :after_initialize, :after_save private def encrypt(value) # Secrecy is committed end def decrypt(value) # Secrecy is unveiled end end
before_save EncryptionWrapper.new("credit_card_number")
って書くとbefore_save
のときにEncryptionWrapper.new("credit_card_number").before_save(self)
が呼ばれます。
つまり、渡されたオブジェクトに対してbefore_save
を委譲できるという機能というかapiです。
みんなやっているのか?
ひとまず参考資料をさがしてみることに。
ActiveRecord::Callbacks
9.2 Callbacks | Advanced Active Record in Rails 4 | InformIT
てめえらのRailsはオブジェクト指向じゃねえ!まずはCallbackクラス、Validatorクラスを活用しろ! - Qiita
ruby - Rails: monkey-patching ActiveRecord::Base vs creating a Module - Stack Overflow
以下の、オープンソースのrailsプロジェクトがまとまっているサイトがあるのですが、コールバック用クラスの実装にであえませんでした。
Open Source Rails
GitLabで似たようなことをやっているようなソースも有りましたが、細かいところまでは読めませんでした。
今後どうしていくか
コールバックを別クラスに書くことは悪くはないのだが、そもそもコールバックの処理が肥大化していきそうで、あんまり良くないかなと思っている(ユーザ側に関係ない処理であれば良い)。
加えて、既存のrailsプロジェクトであまり行われていなさそうということも今回の調査でわかった。
よって、app/callbacks
みたいなディレクトリは作らず、もしコールバックの処理が複数のクラスで共通になったり、肥大化していった場合には、いったんapp/models
に作る。