0
0

[Rails] ActiveModelは何をしているのか

Last updated at Posted at 2023-12-07

ActiveModelはActiveRecordっぽいオブジェクトを作るために使えるという程度の認識だったので、少し理解を深めたくて調査しました。この記事では、ActiveModel::Dirtyに焦点を当てます。

代表的な使い方

class Person
  include ActiveModel::Dirty

  define_attribute_methods :name

  def initialize
    @name = nil
  end

  def name
    @name
  end

  def name=(val)
    name_will_change! unless val == @name
    @name = val
  end

  def save
    # do persistence work

    changes_applied
  end

  def reload!
    # get the values from the persistence layer

    clear_changes_information
  end

  def rollback!
    restore_attributes
  end
end

重要なのは、savereload!rollback!の三兄弟です。これらのメソッドでは、それぞれchanges_appliedclear_changes_informationrestore_attributesが使われています。これらのメソッドが、すなわちsave、reload、rollbackに対応している訳です。

実際に何が行われているのか確認するために、change_appliedメソッドを読んでみましょう。

changes_appliedメソッド

    # Clears dirty data and moves +changes+ to +previous_changes+ and
    # +mutations_from_database+ to +mutations_before_last_save+ respectively.
    def changes_applied
      unless defined?(@attributes)
        mutations_from_database.finalize_changes
      end
      @mutations_before_last_save = mutations_from_database
      forget_attribute_assignments
      @mutations_from_database = nil
    end

解説するまでもなく、コメントに処理内容が書いてありますね(笑)。

ActiveModelのインスタンスには、database(上の変更)をエミュレートするためのオブジェクトが二つ用意されています。一つ前の変更内容(mutation_before_last_save)と現在の変更内容(mutations_from_database)ですね。

changes_appliedでは、現在の変更内容を一つ前の変更内容へとシフトさせています。このように、データベースの変更をエミュレートすることで、あたかも背後にデータベースがあるかのような振る舞いが可能になり、ActiveRecordの代わりとして使えるようになっています。

使ってみよう

  • 値の変更チェック
p = Person.new

p.name = "Tanaka"
p.save

pp p.name_changed? # => false

p.name = "Suzuki"

pp p.name_changed? # => true
  • 値の変更履歴
p = Person.new

p.name = "Tanaka"
p.save
p.name = "Suzuki"
p.save
p.name = "Kondo"

pp p.name # => Kondo
pp p.name_was # => Suzuki
pp p.name_previously_was # => Tanaka
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0