はじめまして!
8月にインゲージに入社したエンジニア1年生の @shutooike です!(保険)
突然ですが、弊社サービスの設定系のテーブルにはその設定を誰が作成・更新したものかを記録するために created_by
, updated_by
というログインユーザーのIDを入れるカラムがあります。
その created_by
, updated_by
にログインユーザーIDをセットする処理は、単に save(updated_by: current_user.id)
としているところもあれば、before_save
などのコールバックでセットしているところもありモデルごとにバラバラでした。
そこらへんいい感じにしてよと @ishiyu に言われたので、負債返却週間 *1で処理の共通化をした話をします!
実装①:コールバック編 🤙
方針:before_validation
コールバックでログインユーザー(操作ユーザー)のIDをセットする
require 'active_support/concern' module Concerns::Userstamp extend ActiveSupport::Concern #---------------------------------------- # Included #---------------------------------------- included do # CALLBACKS before_validation :set_operator_id # VALIDATIONS validates :created_by, presence: true validates :updated_by, presence: true end private def set_operator_id self.created_by = operator_id if self.new_record? self.updated_by = operator_id end def operator_id User.current.id # User.current は devise でいうところの `current_user` を呼び出せるようなメソッド end end
この Userstamp モジュールをモデルに include することで、作成・更新時は created_by
, updated_by
のことを考えなくてよくなりました。
※ コールバックが走らないメソッドは別です。
レビューにて 📝
@shutooike:
できましたレビューお願いします〜
@ishiyu:
お!いい感じだね〜
ただ、access_token
のような内部で自動更新する場合は updated_by
変えたくないんだよね〜
save(touch: false)
ってしたら updated_at
更新されないからそのノリで使いたい
@shutooike:
たしかに 🦀
実装②:黒魔術編 🔮
方針:ActiveRecord の Timestamp モジュールのメソッドをオーバーライドして save(touch: false)
で updated_by
の更新しないようにする
rails/activerecord/lib/active_record/timestamp.rb github.com
require 'active_support/concern' module Concerns::Userstamp extend ActiveSupport::Concern private def _create_record self.created_by = operator_id self.updated_by = operator_id super end # Rails6 では引数がなくなるので、バージョンアップ時に修正する必要あり def _update_record(*args, touch: true, **options) if touch && self.has_changes_to_save? self.updated_by = operator_id end super(*args, touch: touch, **options) end def operator_id User.current.id # User.current は devise でいうところの `current_user` を呼び出せるようなメソッド end end
private メソッドをオーバーライドするという若干トリッキーなことをしていますが、これで save(touch: false)
とした時は updated_at
と同様に updated_by
を更新しないようになりました!
ちなみにこのコードは Rails 5 系でしか動かないので注意してください。
さいごに
大いなる力には、大いなる責任が伴うことを忘れてはいけない
とりあえずいつものやつ置いときます 😎
他にいいやり方があればぜひ教えてください!
ではまた 🙋♂️🙋♂️🙋♂️
*1:弊社で毎月第1週に行っている名前通り負債を返却する週間