71

DB列があり、モデルオブジェクトを作成および更新するときに、Railsがそれらの値を自動的に設定する場合created_atupdated_atそれらの列に触れずにモデルを保存する方法はありますか?

いくつかのレガシーデータを持ち込み、(異なる名前の)レガシーデータフィールドの対応する値からそれらの値を設定したいと思います。それらをモデルに設定してからモデルを保存すると、Railsが入力値をオーバーライドしているように見えます。

もちろん、それを防ぐためにRailsモデルの列に別の名前を付けることもできますが、データがインポートされた後、Railsに自動タイムスタンプ処理を実行させたいと思います。

4

12 に答える 12

81

これは、移行またはレーキタスク(またはエッジレールを使用している場合は新しいデータベースシード)で実行します。

ActiveRecord::Base.record_timestamps = false
begin
  run_the_code_that_imports_the_data
ensure
  ActiveRecord::Base.record_timestamps = true  # don't forget to enable it again!
end

安全に手動で設定できcreated_atupdated_atRailsは文句を言いません。

注:これは、個々のモデルでも機能します。 User.record_timestamps = false

于 2009-05-14T13:31:49.027 に答える
58

代わりにupdate_columnメソッドを使用してください。

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

update_column(name, value)
# Updates a single attribute of an object, without calling save.

検証はスキップされます。

コールバックはスキップされます。

updated_at / updated_on列が使用可能な場合、その列は更新されません。

新しいオブジェクトで呼び出されたとき、またはname属性が読み取り専用としてマークされたときに、ActiveRecordErrorを発生させます。

于 2012-06-24T21:30:49.403 に答える
42

Rails 5は、タイムスタンプを更新せずにレコードを更新する便利な方法を提供しますupdated_athttps ://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save

touch:falseあなたは、あなたの記録を更新している間、ただ合格する必要があります。

>> user = User.first
>> user.updated_at
=> Thu, 28 Apr 2016 20:01:57 IST +05:30
>> user.name = "Jose"
>> user.save(touch: false)
=> true

>> user.updated_at
=> Thu, 28 Apr 2016 20:01:57 IST +05:30
于 2016-05-12T17:06:56.863 に答える
30

移行内で次のように設定できます。

ActiveRecord::Base.record_timestamps = false

または、代わりにupdate_allを使用します。

update_all(updates、conditions = nil、options = {})

提供された一連の条件に一致する場合、指定された詳細ですべてのレコードを更新します。制限と順序も提供できます。このメソッドは、単一のSQL UPDATEステートメントを作成し、それをデータベースに直接送信します。関連するモデルをインスタンス化せず、ActiveRecordコールバックをトリガーしません。

于 2009-05-14T04:00:04.750 に答える
13

Rails 3+では、単一のオブジェクトの場合、record_timestampsクラスではなくオブジェクトに設定します。つまり、

>> user = User.first
>> user.updated_at
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00
>> user.name = "Jose"
=> "Jose"
>> user.record_timestamps = false
>> user.save
=> true
>> user.updated_at
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00
>> User.record_timestamps
=> true

このように、モデルのグローバル状態に触れる必要はなく、ensureブロック内の以前の設定を復元することを覚えておく必要はありません。

于 2016-07-20T22:19:17.893 に答える
3

これは1回限りのインポートであるため、次のように実行できます。

  1. legacy_created_atおよびlegacy_updated_atフィールドを使用してモデルを作成します。
  2. レガシーデータをロードします。必要に応じてモデルフィールドにマップします。使用することができ#save、通常は使用などについて心配する必要はありませんupdate_all。また、必要に応じてコールバックを使用できます。
  3. 移行を作成して、列の名前をcreated_atとに変更しますupdated_at
于 2009-05-14T04:11:06.737 に答える
3

ミックスインモジュールを使用して、ブロック内のタイムスタンプを一時的にオフにするのが好きです。

module WithoutTimestamps
  def without_timestamps
    old = ActiveRecord::Base.record_timestamps
    ActiveRecord::Base.record_timestamps = false
    begin
      yield
    ensure
      ActiveRecord::Base.record_timestamps = old
    end
  end
end

その後、必要な場所で使用できます

class MyModel < ActiveRecord::Base
  include WithoutTimestamps

  def save_without_timestamps
    without_timestamps do
      save!
    end
  end
end

または、次のように1回限りです。

m = MyModel.find(1)
WithoutTimestamps.without_timestamps do
  m.save!
end
于 2013-10-21T21:12:32.387 に答える
3

他の回答を参照すると、次のように、単一のモデルのタイムスタンプを無効にすることに驚きました。

User.record_timestamps = false

私の開発データベースでは機能しましたが、別のサーバーで実行されている実稼働前のデータベースでは機能しませんでした。ただし、すべてのモデルのタイムスタンプを無効にすると機能します

ActiveRecord::Base.record_timestamps = false

(状況:移行でcreated_at属性を変更する)

于 2014-03-19T07:58:53.900 に答える
2

一括インポートを行わない場合は、should_record_timestampsをオーバーライドできますか?モデルのメソッドを使用して、updated_at列をいつ更新するかに関する新しいチェックを追加します。

于 2013-10-08T22:39:13.393 に答える
1

または、スレッドセーフについては、http ://www.hungryfools.com/2007/07/turning-off-activerecord-timestamp.htmlを参照してください。

于 2010-12-16T00:22:57.247 に答える
0

ActiveRecord::Base.record_timestampsフラグを変更することはできませんでした。唯一の有効な方法は、次を使用することActiveRecord::Base.no_touching {}です。

ActiveRecord::Base.no_touching do
  Project.first.touch  # does nothing
  Message.first.touch  # does nothing
end

Project.no_touching do
  Project.first.touch  # does nothing
  Message.first.touch  # works, but does not touch the associated project
end

ここから撮影。

created_atこれは、ユーザーが属性または属性に依存している場合や、列の並べ替えとして使用されている場合に、関連性の高いモデルの一部のプロパティをオーバーライドする必要があり、内部コールバックを気にしたくないレーキタスクに非常に役立ちupdated_atます。

于 2018-08-30T14:37:42.837 に答える
0

私はパーティーに遅れていますが、これがupdated_at私の店での更新をスキップする方法です:

# config/initializers/no_timestamping.rb
module ActiveRecord
  class Base

    def update_record_without_timestamping
      class << self
        def record_timestamps; false; end
      end

      save!

      class << self
        remove_method :record_timestamps
      end
    end

  end
end

使用法:

post.something = 'whatever'
post.update_record_without_timestamping
于 2019-09-26T19:31:26.343 に答える