Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails 7: belongs_to関連付けに変更トラッキングが追加(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Rails 7: belongs_to関連付けに変更トラッキングが追加(翻訳)

アップデートとしては地味でも、Railsユーザーにとって嬉しさ最大の機能が登場することがあります。Railsの最近のアップデートで、belongs_to関連付けの変更を監視する機能が導入されました。Rails wayに沿って進めたい開発者にとっては大歓迎です。

変更トラッキングは、Railsですぐ使える便利メソッドの一種です。Active Recordを使っていると、データベースで変更が生じているかどうかを調べられます。これはトリガーやイベントをビルドするときに便利です。サンプルを見てみましょう。

データベース構造に投稿(Post)とカテゴリ(Category)があるとします。

class Post
  belongs_to :category
end

class Category
  has_many :posts
end

投稿のタイトルが変更されたときのアクティビティを記録しておきたいとします。これは以下のように書けます。

class Post
  belongs_to :category

  before_update :record_activity

  private
  def record_activity
    if self.title_changed?
      # record an activity
    end
  end
end

title属性の値が変更されたかどうかはtitle_changed?メソッドで監視できます。

変更前

同じことを、投稿のカテゴリが変更された場合についてもやってみましょう。

class Post
  belongs_to :category

  before_update :record_activity

  private
  def record_activity
    if self.category_id_changed?
      # アクティビティを記録する
    end
  end
end

この書き方は目障りですね。categoryという関連付けがあるにもかかわらず、その関連付けの変更を追えないので、category_idの変更を監視するというかなり大雑把な方法を取らざるを得ません。これではRails wayから遠ざかってしまいます。

変更後

ありがたいことに、Rails 7でこれを行う方法が導入されます(#42751)。これなら以下のように書けます。

class Post
  belongs_to :category

  before_update :record_activity

  private
  def record_activity
    if self.category_changed?
      # アクティビティを記録する
    end
  end
end

この関連付け名_changed?メソッドは、元と異なる関連付けオブジェクトが代入されている場合はtrueを返し、次回のsave!で外部キーが更新されます。

また、関連付け名_previously_changed?を使えば、以下のように直前のsaveで関連付けが更新されて元と異なる関連付けオブジェクトを参照する場合はtrueを返すこともできます。

  post.category # => #<Post category_id: 123, title: "Welcome to Rails!">
  post.category_previously_changed? # => false

  post.category = Category.second # => #<Post category_id: 456, title: "Welcome to Rails!">
  post.save!

  post.category_previously_changed? # => true

関連記事

Rails 6.1: Active Storageのファイルをプロキシ経由で配信する(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。