Как проверить изменения базы данных записей в памяти?

Я хочу проверить, был ли экземпляр 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

Кажется, это работает, но мне интересно, есть ли встроенный способ поиска изменений в базе данных?

7 голосов | спросил Stefan 29 J000000Tuesday14 2014, 14:06:49

3 ответа


0

После комментария Зелёный Я просмотрел 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 - это та же запись, только что извлеченная из базы данных ( эта строка взята из reload, спасибо emaillenin ).
  • В цикле каждый (свежий) атрибут сравнивается с соответствующим (в памяти) атрибутом. Если они различаются, он добавляется в хеш @changed_attributes. Эта строка происходит из метода ActiveRecord dup. (это на самом деле из закрытого метода, вызываемого dup и _field_changed тоже приватный. Возможно, лучше использовать публичный API ActiveRecord, но мне было лень)
  • Наконец, refresh возвращает self для удобства, так же как reload.

Вот пример использования:

p1 = Product.first
p1.name           #=> "some name"
p1.changed?       #=> false

p2 = Product.first
p2.name = "other name"
p2.save           #=> true

p1.refresh
p1.name           #=> "some name"
p1.changed?       #=> true
p1.name_changed?  #=> true
p1.name_was       #=> "other name"

p1.name = "other name"
p1.name_changed?  #=> false

p1.changed?       #=> true
p1.changes        #=> {"updated_at"=> [Tue, 29 Jul 2014 21:58:57 CEST +02:00, Tue, 29 Jul 2014 15:49:54 CEST +02:00]}
ответил Stefan 30 J000000Wednesday14 2014, 00:36:08
0

Для этого Rails может использовать метод перезагрузки на объекте ActiveRecord.

  def database_changed?
    attributes != reload.attributes
  end

Код доступен в этом новом репо .

Терминал 1

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

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 >
ответил Lenin Raj Rajasekaran 29 J000000Tuesday14 2014, 15:09:35
0
def database_changed?
  self.class.where(self.class.arel_table[:updated_at].gt(updated_at)).exists? self
end
ответил Kyle Decot 29 J000000Tuesday14 2014, 16:13:07

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132