どうすればこれを達成できますか?
と呼ばれる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)でさえ、何も更新しません。
何かアドバイス?ページヒットをカウントするためだけに別のテーブルを作成する必要はありません。
Railsタイムスタンプフィールド? の自動更新を回避する方法はありますか?
またはあなたの質問に近い:
http://blog.bigbinary.com/2009/01/21/override-automatic-timestamp-in-activerecord-Rails.html
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
カウンターをインクリメントするだけなら、代わりにincrement_counter
メソッドを使用します。
ModelName.increment_counter :pagehit, id
これを行うことはお勧めできません。
self.class.update_all({ pagehit: pagehit+1 }, { id: id })
そのはず
self.class.update_all("pagehit = pagehit + 1", { id: id })
その理由は、2つのリクエストが並行している場合、最初のバージョンでは、Rubyメモリに保存されている番号を使用するため、両方が同じ数でページヒットを更新します。これらのクエリのうち2つが同時に発生した場合、1ずつ数を増やすために、サーバーはそれらを次々に処理し、正しい数のページヒットで終了します。
Monkeypatchingのトラブルを回避するには、この目的でModelName.update_allを使用することもできます。
def increment_pagehit
self.class.update_all({ pagehit: pagehit+1 }, { id: id })
end
これは、レコードのタイムスタンプにも影響しません。
精度がそれほど重要ではなく、コードが何度も実行されるとは思わない場合は、データベースに保存されている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
で置き換えません。