我想检查ActiveRecord
实例是否已按数据库方式更改。类似的东西:
p1 = Product.first
p1.name #=> "some name"
p2 = Product.first
p2.name = "other name"
p2.save #=> true
p1.database_changed? #=> true
我目前正在将记录的属性与持久属性进行比较:
class Product < ActiveRecord::Base
def database_changed?
Product.find(id).attributes != attributes
end
end
这似乎有效,但我想知道是否有内置的方法来查找数据库更改?
答案 0 :(得分:3)
在Зелёный's comment之后我审核了ActiveModel::Dirty
,并意识到它几乎可以实现我的目标。已经存在内存状态(记录的属性)和数据库状态(由ActiveModel::Dirty
处理)。我只需要一种方法来更新数据库状态,保持内存状态不变:
def refresh
@changed_attributes = {}
fresh_object = self.class.unscoped { self.class.find(id) }
fresh_object.attributes.each do |attr, orig_value|
@changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
end
self
end
@changed_attributes
是ActiveModel::Dirty
的哈希值,用于存储更改的值。我们显然必须重置它。fresh_object
是从数据库中新获取的相同记录(this line来自reload
,感谢emaillenin)。 @changed_attributes
哈希。 This line来自ActiveRecord
的{{1}}方法。 (它实际上来自dup
调用的私有方法,而dup
也是私有的。使用_field_changed
的公共API可能更好,但我很懒。)ActiveRecord
返回refresh
,就像self
一样。以下是一个示例用法:
reload
答案 1 :(得分:1)
Rails的方法是在ActiveRecord对象上使用reload方法。
def database_changed?
attributes != reload.attributes
end
此新代码repo中提供了此代码。
2.1.2 :001 > c = Car.find(1)
Car Load (0.4ms) SELECT "cars".* FROM "cars" WHERE "cars"."id" = ? LIMIT 1 [["id", 1]]
=> #<Car id: 1, name: "Audi", model: "R8", created_at: "2014-07-29 11:14:43", updated_at: "2014-07-29 11:14:43">
2.1.2 :002 > c.database_changed?
Car Load (0.1ms) SELECT "cars".* FROM "cars" WHERE "cars"."id" = ? LIMIT 1 [["id", 1]]
=> false
2.1.2 :003 > c.database_changed?
Car Load (0.2ms) SELECT "cars".* FROM "cars" WHERE "cars"."id" = ? LIMIT 1 [["id", 1]]
=> false
2.1.2 :004 > c.database_changed?
Car Load (0.2ms) SELECT "cars".* FROM "cars" WHERE "cars"."id" = ? LIMIT 1 [["id", 1]]
=> true
2.1.2 :001 > c = Car.find(1)
Car Load (0.2ms) SELECT "cars".* FROM "cars" WHERE "cars"."id" = ? LIMIT 1 [["id", 1]]
=> #<Car id: 1, name: "Audi", model: "R8", created_at: "2014-07-29 11:14:43", updated_at: "2014-07-29 11:14:43">
2.1.2 :002 > c.model = 'A5'
=> "A5"
2.1.2 :003 > c.save!
(0.2ms) begin transaction
SQL (0.3ms) UPDATE "cars" SET "model" = ?, "updated_at" = ? WHERE "cars"."id" = 1 [["model", "A5"], ["updated_at", "2014-07-29 11:15:32.845875"]]
(1.2ms) commit transaction
=> true
2.1.2 :004 >
答案 2 :(得分:1)
def database_changed?
self.class.where(self.class.arel_table[:updated_at].gt(updated_at)).exists? self
end