it-swarm.com.ru

Как обновить один атрибут без сенсорного атрибута updated_at?

Как мне этого добиться?

попытался создать 2 метода, называется 

def disable_timestamps
  ActiveRecord::Base.record_timestamps = false
end

def enable_timestamps
  ActiveRecord::Base.record_timestamps = true
end

и сам метод обновления:

def increment_pagehit
  update_attribute(:pagehit, pagehit+1)
end

включать и выключать временные метки с помощью обратных вызовов, таких как:

before_update :disable_timestamps, :only => :increment_pagehit
after_update :enable_timestamps, :only => :increment_pagehit

но он ничего не обновляет, даже нужный атрибут (pagehit).

Любой совет? Я не хочу создавать другую таблицу только для подсчета количества страниц.

41
Kleber S.
12
apneadiving

В качестве альтернативы update_attribute, в Rails 3.1+ вы можете использовать update_column.

update_attribute пропускает проверки, но прикасается к updated_at и выполняет обратные вызовы.

update_column пропускает проверки, не касается updated_at и не выполняет обратные вызовы.

Таким образом, update_column - отличный выбор, если вы не хотите влиять на updated_at и не нуждаетесь в обратных вызовах.

Смотрите http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html для получения дополнительной информации.

Также обратите внимание, что update_column обновит значение атрибута в модели в памяти и не будет помечено как грязное. Например:

p = Person.new(:name => "Nathan")
p.save
p.update_column(:name, "Andrew")
p.name == "Andrew" # True
p.name_changed? # False
88
Nathan

Если все, что вы хотите сделать, это увеличить счетчик, я бы вместо этого использовал метод increment_counter:

ModelName.increment_counter :pagehit, id
12
idlefingers

это не очень хорошая идея сделать это:

self.class.update_all({ pagehit: pagehit+1 }, { id: id })

так должно быть

self.class.update_all("pagehit = pagehit + 1", { id: id })

причина в том, что если два запроса параллельны, в первой версии оба обновят заголовки страниц с одинаковым номером, так как он использует число, сохраненное в памяти Ruby. Второй вариант использует сервер sql для увеличения числа на 1, в случае, если два из этих запросов поступают одновременно, сервер будет обрабатывать их один за другим и получит правильное количество страниц.

2
Tom Caspy

Чтобы избежать Monkeypatchingtroubles, вы также можете использовать ModelName.update_all для этой цели:

def increment_pagehit
  self.class.update_all({ pagehit: pagehit+1 }, { id: id })
end

Это также не касается временных меток записи.

2
fredostarr

У вас также есть decrement и increment (и их версии взрыва), которые не изменяют updated_at, не запускают обратные вызовы проверки правильности и, очевидно, удобны для счетчиков/целых чисел.

1
tirdadc

Если точность не так уж важна, и вы не ожидаете, что код будет выполняться много раз, вы можете попробовать изменить сохраненное в базе данных значение updated_at, например, так:

u = User.first
u.name = "Alex 2" # make some changes...
u.updated_at = u.updated_at + 0.000001.second # alter updated_at
u.save

так что Rails действительно попытается сохранить то же значение, а не заменить его на Time.now.

0
glampr