web-dev-qa-db-ja.com

touch 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)でさえ、何も更新しません。

何かアドバイス?ページヒットをカウントするためだけに別のテーブルを作成する必要はありません。

42
Kleber S.

Railsタイムスタンプフィールド? の自動更新を回避する方法はありますか?

またはあなたの質問に近い:

http://blog.bigbinary.com/2009/01/21/override-automatic-timestamp-in-activerecord-Rails.html

11
apneadiving

update_attributeの代わりに、In 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
91
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 })

その理由は、2つのリクエストが並行している場合、最初のバージョンでは、Rubyメモリに保存されている番号を使用するため、両方が同じ数でページヒットを更新します。これらのクエリのうち2つが同時に発生した場合、1ずつ数を増やすために、サーバーはそれらを次々に処理し、正しい数のページヒットで終了します。

2
Tom Caspy

Monkeypatchingのトラブルを回避するには、この目的で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