Rails API: ActiveModel::Dirty
(翻訳)
ActiveModel::Dirty
は、Active Recordと同じ方法でオブジェクトの変更をトラッキングする方法を提供します。
ActiveModel::Dirty
を実装するうえで守るべき要件は以下のとおりです。
- 自分のオブジェクト内に
include ActiveModel::Dirty
を書く -
define_attribute_methods
を呼び出して、トラッキングしたい個別のメソッドを渡す -
トラッキング対象属性を変更する前には
属性名_will_change!
を呼び出す -
変更が永続化された後は、
changes_applied
を呼び出す -
変更情報をリセットしたい場合は、
clear_changes_information
を呼び出す -
直前のデータを復元したい場合は
restore_attributes
を呼び出す
最小限の実装は以下のようになります。
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
# 永続化を行う
changes_applied
end
def reload!
# 永続化層から値を取得する
clear_changes_information
end
def rollback!
restore_attributes
end
end
このPerson
オブジェクトを新しくインスタンス化したときは「変更なし」の状態になります。
person = Person.new
person.changed? # => false
name
属性の変更をチェックする:
person.name = 'Bob'
person.changed? # => true
person.name_changed? # => true
person.name_changed?(from: nil, to: "Bob") # => true
person.name_was # => nil
person.name_change # => [nil, "Bob"]
person.name = 'Bill'
person.name_change # => [nil, "Bill"]
- 変更を保存する:
person.save
person.changed? # => false
person.name_changed? # => false
- 変更をリセットする:
person.previous_changes # => {"name" => [nil, "Bill"]}
person.name_previously_changed? # => true
person.name_previously_changed?(from: nil, to: "Bill") # => true
person.name_previous_change # => [nil, "Bill"]
person.name_previously_was # => nil
person.reload!
person.previous_changes # => {}
- 変更をロールバックする:
person.name = "Uncle Bob"
person.rollback!
person.name # => "Bill"
person.name_changed? # => false
- 属性に同じ値を代入した場合は「変更なし」とする:
person.name = 'Bill'
person.name_changed? # => false
person.name_change # => nil
- どの属性が変更されたかを調べる:
person.name = 'Bob'
person.changed # => ["name"]
person.changes # => {"name" => ["Bill", "Bob"]}
Active Modelで属性の値を破壊的に変更する場合は、属性名_will_change!
を呼び出してその属性が変更されることをマーキングしてください。そうしないと、属性の変更をActive Modelでトラッキングできなくなります。
ただし、Active Recordではそうした変更は自動的に検出されるので、Active Modelモデルでは属性名_will_change!
を呼び出す必要はありません。
person.name_will_change!
person.name_change # => ["Bill", "Bill"]
person.name << 'y'
person.name_change # => ["Bill", "Billy"]
name
属性のメソッドは、name_changed?
のように呼び出すことも、汎用のattribute_changed?("name")
に引数"name"
を渡して呼び出すことも可能です。
🔗 メソッド
属性名_change
属性名_changed?
属性名_previous_change
属性名_previously_changed?
属性名_previously_was
属性名_was
属性名_will_change!
A
C
changed
changed?
changed_attributes
changes
changes_applied
clear_属性名_change
clear_attribute_changes
clear_changes_information
P
R
include
されるモジュール
🔗 publicインスタンスメソッド
🔗 属性名_change
このメソッドは属性ごとに生成されます。
属性の古い値と新しい値を返します。
person = Person.new
person.name = 'Nick'
person.name_change # => [nil, 'Nick']
🔗 属性名_changed?
このメソッドは属性ごとに生成されます。
属性に未保存の変更が存在する場合にtrue
を返します。
person = Person.new
person.name = 'Andrew'
person.name_changed? # => true
🔗 属性名_previous_change
このメソッドは属性ごとに生成されます。
最後に保存したときの値とその直前の値を返します。
person = Person.new
person.name = 'Emmanuel'
person.save
person.name_previous_change # => [nil, 'Emmanuel']
🔗 属性名_previously_changed?(**options)
このメソッドは属性ごとに生成されます。
その属性を保存する前に未保存の変更が存在していた場合にtrue
を返します。
person = Person.new
person.name = 'Britanny'
person.save
person.name_previously_changed? # => true
person.name_previously_changed?(from: nil, to: 'Britanny') # => true
🔗 属性名_previously_was
このメソッドは属性ごとに生成されます。
最後に保存したときの直前の値を返します。
person = Person.new
person.name = 'Sage'
person.save
person.name_previously_was # => nil
🔗 属性名_was
このメソッドは属性ごとに生成されます。
その属性の古い値を返します。
person = Person.new(name: 'Steph')
person.name = 'Stephanie'
person.name_was # => 'Steph'
🔗 属性名_will_change!
このメソッドは属性ごとに生成されます。
Active Modelで属性を破壊的に変更する場合は、属性名_will_change!
を呼び出してその属性が変更されることをマーキングしてください。そうしないと、属性の変更をActive Modelのモデルでトラッキングできなくなります。
ただし、Active Recordではそうした変更は自動的に検出されるので、Active Modelモデルでは*_will_change!
を呼び出す必要はありません。
person = Person.new('Sandy')
person.name_will_change!
person.name_change # => ['Sandy', 'Sandy']
🔗 attribute_changed?
(attr_name, **options)
属性名_changed?
メソッドと同じですが、属性名を指定できます。
🔗 attribute_previously_changed?
(attr_name, **options)
属性名_previously_changed?
メソッドと同じですが、属性名を指定できます。
🔗 attribute_previously_was
(attr_name)
属性名_previously_was
メソッドと同じですが、属性名を指定できます。
🔗 attribute_was
(attr_name)
属性名_was
メソッドと同じですが、属性名を指定できます。
🔗 changed
()
変更が未保存の属性名リストを配列として返します。
person.changed # => []
person.name = 'bob'
person.changed # => ["name"]
🔗 changed?
変更が未保存の属性が1個以上存在する場合はtrue
を返し、それ以外の場合はfalse
を返します。
person.changed? # => false
person.name = 'bob'
person.changed? # => true
🔗 changed_attributes
()
変更が未保存の属性名と元の値のリストをハッシュとして返します(例: 属性名 => 元の値
)。
person.name # => "bob"
person.name = 'robert'
person.changed_attributes # => {"name" => "bob"}
🔗 changes
()
変更された属性名と「元の値と新しい値」のリストをハッシュとして返します(例: 属性名 => [元の値, 新しい値]
)。
person.changes # => {}
person.name = 'bob'
person.changes # => { "name" => ["bill", "bob"] }
🔗 changes_applied
()
未保存のダーティデータをクリアし、以下を行います。
changes
をprevious_changes
に移動mutations_from_database
をmutations_before_last_save
に移動
🔗 clear_属性名_change
このメソッドは属性ごとに生成されます。
その属性のダーティデータ(現在の変更や直前の変更)をすべてクリアします。
person = Person.new(name: 'Chris')
person.name = 'Jason'
person.name_change # => ['Chris', 'Jason']
person.clear_name_change
person.name_change # => nil
🔗 clear_attribute_changes
(attr_names)
🔗 clear_changes_information
()
すべてのダーティデータ(現在の変更や直前の変更)をクリアします。
🔗 previous_changes
()
モデルが保存される前に変更された属性のリストをハッシュとして返します。
person.name # => "bob"
person.name = 'robert'
person.save
person.previous_changes # => {"name" => ["bob", "robert"]}
🔗 restore_属性名!
このメソッドは属性ごとに生成されます。
その属性を古い値に戻します。
person = Person.new
person.name = 'Amanda'
person.restore_name!
person.name # => nil
🔗 restore_attributes
(attr_names = changed)
指定したすべての属性を古い値に戻します。
概要
MITライセンスに基づいて翻訳・公開いたします。
ActiveModel::Dirty